TCP:传输控制协议
1:TCP特点:
(1)面向数据流:
(2)有连接(通信之前必须建立连接)
(3)安全可靠的传输机制
(4)机制复杂,网络资源开销大,
(5)本质只能实现一对一的通信(使用TCP的并发方式可以实现一对多通信)
2:TCP确保安全可靠的机制:
三次握手和四次挥手机制:
三次握手:发生在TCP建立连接时,需要进行三次握手操作,为了确保收发双方在通信之前都已准备数据
SYN:客户端请求和服务端建立连接
ACK:响应报文标志位
三次握手:
TCP四次挥手:TCP断开连接时,需要进行四次挥手,确保断开连接前双方都已通信结束:先发送FIN的一端数据已经发送完了,为防止另一端还在发送数据(数据还没发送完),另一端发送的ACK和FIN不能同时发送,在另一端完全发送完后再发送FIN
FIN:请求断开连接标志位
ACK:响应报文标志位
TCP编程流程:
三次握手阶段:
四次挥手阶段:
服务端close()-》客户端send()的过程
代码:
#include<stdio.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h> /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>
#include<string.h>
int main(void)
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("socket error\n");return -1;}struct sockaddr_in seraddr;seraddr.sin_family=AF_INET;seraddr.sin_port=htons(50000);seraddr.sin_addr.s_addr=inet_addr("192.168.0.120");int ret = connect(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));if(ret <0){perror("connect error\n");return -1;}ssize_t cnt =send(sockfd,"hello world",11,0);if(cnt<0){perror("send error\n");return -1;}printf("cnt = %ld\n",cnt);close(sockfd);return 0;
}
服务端函数:
listen函数:
accept函数:
recv函数:接收通讯套接字-
对方断开链接时,将会返回0。
代码
#include<stdio.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h> /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>
#include<string.h>int main(int argc, const char *argv[])
{//socket()//bind()//listen()//accept()//recv()//send()//close()int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.0.179");int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 10);if (ret < 0){perror("listen error");return -1;}int connfd = accept(sockfd, NULL, NULL);if (connfd < 0){perror("accept error");return -1;}char buff[1024] = {0};ssize_t cnt = recv(connfd, buff, sizeof(buff), 0);if (cnt < 0){printf("recv error");return -1;}printf("cnt = %ld, buff = %s\n", cnt, buff);close(connfd);close(sockfd);return 0;
}
TCP粘包问题:
发送方应用层发送的多包数据将来在接收方可能一次读到,产生了粘连。
1:发送方将应用层的两包数据整合为一包发送。
2:接收方不知道一包数据的字节数,多包数据在接收方缓冲区缓存,在接收时将多包数据一起接收了
解决粘包问题的方法:
1:减慢发送方的发送速度,在每次发送后给它延迟1u秒,usleep(1)。
2:发送方发送指定大小,接收方接收指定大小
指定大小:发送结构体
注意:跨平台间数据传输时要注意结构体对齐问题。
32位平台和64位平台的结构体大小不同。
3:应用层为发送的数据增加分隔符,利用分隔符解析
4:封装数据帧格式进行发送(提前自定义协议)
还要封装帧头和帧尾
AA到BB之间的数据为完整的一帧数据,为防止之间出现帧头或帧尾:
帧头后封装长度
帧头
帧尾
有效数据长度:C0
有效数据:
校验: