文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

TCP服务器—实现数据通信

2023-08-31 05:33

关注

目录

前言

1.接口介绍

2.编写服务器

3.编写客户端

4.编译链接

5.测试

6.总结


        今天我们要介绍的是使用TCP协议实现数据通信,相比于之前写的UDP服务器实现数据信,在主体逻辑上并没有差别。客户端向服务器发送信息,服务器接受信息并回显,因为UDP是面向数据报,而TCP是面向连接的,所以在实现的时候接口上会有一些差别,下面,我们具体来看看UDP和TCP在编码的实现上有什么不同。

因为TCP是面向连接的,所以服务器创建完套接字,然后绑定成功后,将套接字设置为监听套接字

服务器启动之后,首先需要根据监听套接字建立连接,建立连接成功后返回一个新的文件描述符,后续的通信都是按照这个新的文件描述符按照读写文件的形式进行读写数据。

对于客户端来说创建完套接字之后,客户端启动之后首先需要建立连接

listen():设置sock为监听状态

 #include         #include  int listen(int sockfd, int backlog);

sockfd:创建套接字的返回值

backlog:底层全连接队列的长度

accept():服务端建立连接

#include          #include int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd:监听套接字

struct sockaddr* addr:输出型参数,可以获取服务端的IP地址和port端口号

socklen_t* addrlen:结构体的大小

返回值:返回一个新打开的文件描述符

connect():客户端建立连接

#include         #include int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd:创建套接字返回值

struct sockaddr* addr:输出型参数,用来填写需要访问的服务端的IP地址和port端口号

socklen_t addrlen:结构体的大小

tcpServer.hpp

#pragma once#include #include #include #include #include #include #include #include #include "log.hpp"namespace server{    using namespace std;    enum    {        USAGE_ERR = 1,        SOCKET_ERR,        BIND_ERR,        LISTEN_ERR    };    static const uint16_t gport = 8080;    static const int gback = 5;    class TcpServer    {    public:        TcpServer(const uint16_t &port = gport)            : _port(gport), _sock(-1)        {}        void InitServer()        {            _sock = socket(AF_INET, SOCK_STREAM, 0);            if (_sock < 0)            {                logMessage(FATAL, "create socket error");                exit(SOCKET_ERR);            }            logMessage(NORMAL, "create socket success");            // 绑定:            struct sockaddr_in local;            local.sin_family = AF_INET;            local.sin_port = htons(_port);            local.sin_addr.s_addr = INADDR_ANY;            if (bind(_sock, (struct sockaddr *)&local, sizeof(local)) < 0)            {                logMessage(FATAL, "bind socket error");                exit(BIND_ERR);            }            logMessage(NORMAL, "bind socket success");            // 设置sock为监听状态:            if (listen(_sock, gback) < 0)            {                logMessage(FATAL, "listen socket error");                exit(LISTEN_ERR);            }            logMessage(NORMAL, "listen socket success");        }        void start()        {            for (;;)            {                // 建立连接:                struct sockaddr_in peer;                socklen_t len = sizeof(peer);                int sock = accept(_sock, (struct sockaddr *)&peer, &len);                 if (sock < 0)                {                    logMessage(ERROR, "accept error, next");                    continue;                }                logMessage(NORMAL, "accept a new link success");                std::cout << "sock: " << sock << std::endl;                //未来通信全部用sock,面向字节流的,后续全部都是文件操作:                serviceIO(sock);                close(sock);            }        }        void serviceIO(int sock)        {            char buffer[1024];            while(true)            {                ssize_t n = read(sock,buffer,sizeof(buffer)-1);                if(n > 0)                {                    buffer[n] = 0;                    cout << "recvice message: " << buffer << endl;                    string outbuffer = buffer;                    outbuffer += "[server echo]";                    write(sock,outbuffer.c_str(),outbuffer.size());                }                else if(n == 0)                {                    // 代表client退出                    logMessage(NORMAL, "client quit, me too!");                    break;                }            }        }        ~TcpServer()        {}    private:        int _sock;        uint16_t _port;    };}

tcpServer.cc:启动服务器

#include"tcpServer.hpp"#includeusing namespace server;static void Usage(string proc){    cout << "\nUsage:\n\t" << proc << " local_port\n\n";}int main(int argc,char* argv[]){    if(argc != 2)    {        Usage(argv[0]);        exit(USAGE_ERR);    }    uint16_t port = atoi(argv[1]);    unique_ptr tcs(new TcpServer(port));    tcs->InitServer();    tcs->start();    return 0;}

tcpClient.hpp

#pragma once#include #include #include #include #include #include #include #include namespace client{    using namespace std;    class TcpClient    {    public:        TcpClient(const string& serverip,const uint16_t port)        :_serverip(serverip),_port(port),_sock(-1)        {}        void InitClient()        {            _sock = socket(AF_INET,SOCK_STREAM,0);            if(_sock < 0)            {                cerr << "create sock fail" << endl;                exit(-1);            }        }        void start()        {            //建立连接:            struct sockaddr_in server;            server.sin_family = AF_INET;            server.sin_port = htons(_port);            server.sin_addr.s_addr = inet_addr(_serverip.c_str());            if(connect(_sock,(struct sockaddr*)&server,sizeof(server)) != 0)            {                cerr << "connect fail" << endl;            }            else            {                string message;                while(true)                {                    cout << "Please Enter: ";                    getline(cin,message);                    write(_sock,message.c_str(),message.size());                    char buffer[1024];                    int n = read(_sock,buffer,sizeof(buffer)-1);                    if(n > 0)                    {                        buffer[n] = 0;                        cout << "Server回复: " << buffer << endl;                    }                    else                    {                        break;                    }                }            }        }        ~TcpClient()        {            if(_sock >= 0)                close(_sock);        }    private:        string _serverip;        uint16_t _port;        int _sock;    };} // namespace client

tcpClient.cc:启动客户端

#include"tcpClient.hpp"#includeusing namespace client;static void Usage(string proc){    cout << "\nUsage:\n\t" << proc << " serverip serverport\n\n";}int main(int argc,char* argv[]){    if(argc != 3)    {        Usage(argv[0]);        exit(-1);    }    uint16_t port = atoi(argv[2]);    string ip = argv[1];    unique_ptr tcc(new TcpClient(ip,port));    tcc->InitClient();    tcc->start();    return 0;}

makefile:

.PHONY:allall:tcpServer tcpClienttcpServer:tcpServer.ccg++ -o $@ $^ -std=c++11tcpClient:tcpClient.ccg++ -o $@ $^ -std=c++11.PHONY:cleanclean:rm tcpServer tcpClient

 如图所示,服务端和客户端可以完成正常的数据通信了。

        TCP协议和UDP协议在数据通信的实现中,除了一些接口使用的不同之外,其实并没有太大的不同,在之前说的UDP是面向数据报的而TCP是面向字节流的,这些特性又是如何体现的呢?关于这个问题,博主将在后面的文章中会为大家继续进行介绍。不要错过哦!

来源地址:https://blog.csdn.net/qq_65307907/article/details/132168198

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯