当前位置:   article > 正文

TCP通信实现_tcp通信如何实现

tcp通信如何实现
[1] tcp通信原理
    1. 建立连接
    2. 通信
    3. 断开连接
   
[2] TCP实现流程
    1. 头文件
        #include <sys/socket.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>

    2. 数据结构
    3. 实现流程(函数)
       (1) 服务端
           1. 创建监听socket                                          买手机
              /*
               * @param[in] domain 通信领域
               *                  @li AF_UNIX, AF_LOCAL 本机通信
               * @li AF_INET ipv4
               *                  @li AF_INET6 ipv6
               * @li AF_PACKET         底层数据包
               * @param[in] type 套接字类型
               * SOCK_STREAM           流式套接字(TCP)
               * SOCK_DGRAM            报文套接字(UDP)
               * SOCK_RAW              原始套接字(IP、ICMP)
               * @param[in] protocol 指定使用协议,通常是0
               * @return 文件描述符(套接字)
               * @li -1 错误(错误码见errno)
               */
              int socket(int domain, int type, int protocol);


           2. 绑定ip地址(本机)和端口(自己的端口)到监听socket          放SIM卡
              /*
               * @brief 绑定ip地址(本机的)和端口(自己的)到socket
               * @param[in] sockfd  套接字
               * @param[in] addr 地址(通信类型、ip地址和端口号)
               * @param[in] addrlen addr的字节数
               * @return @li 0 绑定成功
               * @li -1 错误(错误码见errno)
               */
              int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);


           3. listen(将socket设置为监听模式)                          开机
              /*
               * @brief 将socket设置为监听模式
               * @param[in] sockfd  套接字
               * @param[in] backlog 设置listen队列的最大连接请求个数
               * @return @li 0 成功
               * @li -1 错误(错误码见errno)
               */
              int listen(int sockfd, int backlog);


           4. accept(接收客户端连接, 创建客户端socket)                接通
              /*
               * @brief 接收客户端连接, 创建跟客户端连接的socket
               * @param[in] sockfd  监听套接字
               * @param[out] addr 客户端地址(ip地址和端口)
               * @param[in | out] addrlen 输入地址缓存的字节数,输出实际地址的字节数
               * @return 文件描述符(客户端套接字)
               * @li -1 错误(错误码见errno)
               * @notes listen请求队列为空时,在阻塞模式下,本函数会阻塞
               */
              int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


           5. 利用客户端socket接收/发送数据                           说话
              /*
               * @brief 发送数据(写数据到发送缓冲区)
               * @param[in] sockfd  客户端套接字
               * @param[in]  buf 要发送的数据
               * @param[in]       len    数据长度
               * @param[in] flags 一般为0
               * @return 成功发送的字节数
               * @li -1 错误(错误码见errno)
               * @notes 一个字节都无法发送时,在阻塞模式下,本函数会阻塞
               *                  send(sockfd, buf, len, 0) <===> write(sockfd, buf, len);
               */
              ssize_t send(int sockfd, const void *buf, size_t len, int flags);

              /*
               * @brief 接收数据(读取数据从接收中缓冲区)
               * @param[in] sockfd  客户端套接字
               * @param[out] buf 放置数据的缓冲
               * @param[in]       len    缓冲区的字节数
               * @param[in] flags 一般为0
               * @return 成功读取的字节数
               * @li -1 错误(错误码见errno)
               * @notes 一个字节都无法接收时,在阻塞模式下,本函数会阻塞
               *                  recv(sockfd, buf, sizeof(buf), 0) <===> read(sockfd, buf, sizeof(buf));
               */
              ssize_t recv(int sockfd, void *buf, size_t len, int flags);


           6. close客户端socket                                       挂机
           7. close监听socket                                         关机
              int close(int fd);

              /*
               * @brief 关闭套接字
               * @param[in] sockfd  套接字
               * @param[in]    how 如何关闭?
               * @li SHUT_RD 关闭读
               * @li SHUT_WR 关闭写
               * @li SHUT_RDWR 关闭读写
               * @return @li 0 成功
               * @li -1 错误(错误码见errno)
               */
              int shutdown(int sockfd, int how);


       (2) 客户端
           1. 创建socket
           2. 绑定ip地址(本机)和端口(自己的端口)到socket(可选)
           3. 建立连接(connect)
              /*
               * @brief 连接服务端
               * @param[in] sockfd  套接字
               * @param[in]  addr  服务端地址(ip和端口)
               * @param[in]       addrlen 地址字节数
               * @return @li 0                 成功
               * @li -1 错误(错误码见errno)
               * @notes 正在连接时,在阻塞模式下,本函数会阻塞,但阻塞有超时时间
               */
              int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);


           4. 发送/接收数据
           5. 关闭socket
[3] udp聊天室
    1. 简单的多人聊天
       见《4.udp聊天室》
       
    2. 标准聊天
       (1) 登陆(功能 名字)
       (2) 聊天(功能 内容)
       (3) 退出(功能)
       
       1. 制定协议
          打包(数据组合)   1. 结构体     2. 按顺序放数据到缓存
         
          1. 结构体分析
             typedef struct {
               // char c;
               // 中间会空3个字节

               int func;
               char c;
               char *p;
             } PROL ;


                    客户端            服务器      错误原因                                        解决
           字节序    小端             大端       func会错误,func有四个字节,字节顺序正好相反     统一使用大端(htonl/ntohl htons/ntohs)
           位数      32bit            64bit      机器理解int类型的时候,位数不同                  系统没有提供统一方法,程序自己保证位数相同
           对齐      32bit            64bit      因为结构体程序对齐,很可能导致中间,空闲的字节   认真设计结构体,是它尽量不出现因为需要对齐,而空出内存
                                                 数,不相同而导致解析错误  
           对于初学者,如果需要考虑数据传输完全正确,不要使用结构体。
           
          2. 按顺序放数据到缓存
             最简单的方法,保证协议中的数据都是以字节为单位
             
             300        "300"
             2.7        "2.7"
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/425998
推荐阅读
相关标签
  

闽ICP备14008679号