TCP是一种面向广域网的通信协议,目的是在跨越多个网络通信时,为两个通信端点之间提供一条具有下列特点的通信方式:
1、面向连接
2、可靠的(数据无丢失 、数据无失序 、数据无错误 、数据无重复到达)
3、基于字节流传输层协议
使用严格的应答机制来保证可靠性
严格的应答机制是指其建立连接时需要进行三次握手、断开连接时需要进行四次挥手操作
TCP三次握手
SYN:表示请求连接 ACK:表示应答 FIN:表示请求断开
第一次握手:client ------> server SYN = 1 客户端发送 SYN 标志的数据包给服务器
第二次握手:server-----> client SYN = 1, ACK = 1 服务器发送 SYN+ACK标志的数据包给客户端
第三次握手:client ----> server,ACK = 1 客户端发送 ACK 标志的数据包给服务器
如图所示:
TCP 四次挥手
第一次挥手:client -----> server FIN 客户端发送 FIN 标志的数据包给服务器
第二次挥手: server -----> client ACK 服务器发送 ACK 标志的数据包给客户端
第三次挥手: server -----> client FIN 服务器发送 FIN 标志的数据包给客户端
第四次挥手:client -----> server ACK 客户端发送 ACK 标志的数据包给服务器
注:1、每次发送数据后,都必须要应答
2、会给每个数据包编号,应答时区分
TCP服务器的设计流程
1: 建立套接字
2: 绑定ip地址与端口号
3: 建立监听队列,让套接字进入到被动监听状态
4: 接受连接,产生新的套接字
5: 数据读写(接收、发送)
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[])
{
int ret;
int sfd,cfd;
ssize_t recv_bytes,read_bytes;
char buf[128] = {0};
struct sockaddr_in src,cli;
socklen_t len = sizeof(src);
socklen_t addrlen = sizeof(cli);
sfd = socket(AF_INET,SOCK_STREAM,0);//创建套接字
if(sfd == -1)
{
perror("socket fail");
return -1;
}
printf("sfd:%d\n",sfd);
src.sin_family = AF_INET;
src.sin_port = htons(atoi(argv[2]));
src.sin_addr.s_addr = inet_addr(argv[1]);
ret = bind(sfd,(const struct sockaddr *)&src,len);//绑定地址
if(ret == -1)
{
perror("bind");
return -1;
}
ret = listen(sfd,10);//将套接字设定为被动监听状态,监听客户端的连接请求
if(ret == -1) //10为未决队列长度
{
perror("listen");
return -1;
}
cfd = accept(sfd,(struct sockaddr *)&cli,&addrlen);//接收客户端连接请求,产生套接字
if(cfd == -1) //用于和客户端通信,通过cli保存客户端ip地址和port口号
{
perror("accept");
return -1;
}
printf("client IP: %s PORT %d\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
while(1)
{
memset(buf,0,sizeof(buf));
recv_bytes = recv(cfd,buf,sizeof(buf),0);//接收客户端发送的数据
if(recv_bytes == -1)
{
perror("recv");
return -1;
}else if(recv_bytes == 0)
{
printf("client shutdown\n");
break;
}
printf("buf:%s\n",buf);
read_bytes = send(cfd,buf,strlen(buf),0);//返回数据
if(read_bytes == -1)
{
perror("read");
return -1;
}
}
close(sfd);
close(cfd);
return 0;
}