一、TCP协议提供的是面向连接的可靠的流式服务
即有发送缓冲区、接收缓冲区,发送次数和接收次数不一定对等。报头长,成本高,需要搭载更多的数据。
二、三次握手建立连接与四次挥手断开连接
1.三次握手
通过对ACK的确认,建立可靠连接。有超时重传机制
2.四次挥手
有可能服务器处理数据的时间较短,即三次挥手
3.状态图
TIME_WAIT 状态: 出现在主动发起断开链接请求的一端
意义:1、保证可靠的终止 TCP 链接
2、保证迟来的数据报能被识别并丢弃
4.TCP状态转移过程
红线: 客户端发起链接
绿线: 服务器接收链接
蓝线: 主动断开链接的过程
紫线: 被动断开链接的过程
5.TCP报头
三、TCP 的编程流程:
server: socket bind listen accept recv/send close client: socket /*bind*/
connect recv/send close
int socket(int domain, int type, int protocol);
domain:: 协议簇 AF_INET
type:: 选择协议 SOCK_STREAM(tcp) SOCK_DGRAM(udp)
protocol:: 0
int bind(int sockfd, struct sockaddr *addr, int addrlen);
addr:: 指定 IP 地址和端口号
struct sockaddr_in
{
sa_family_t sin_family; // 地址簇 AF_INET
u_int16_t sin_port; // 端口号 网络字节序(大端模式) PC 机(小端模式) struct in_addr sin_addr; //IP 地址
}
struct in_addr
{
u_int32_t s_addr; // IP 地址最终的表示
}
int listen(int sockfd, int size);
int accept(int sockfd, struct sockaddr *addr, int *addrlen);
返回值: 获取到的和客户端连接的文件描述符
addr:; 记录客户端的 IP 地址和端口号
int connect(int sockfd, struct sockaddr* addr, int addrlen);
addr:: 要连接的服务器的 IP 地址和端口号
四、代码实现
1.服务器端
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in ser ,cli;
ser.sin_family = AF_INET;
ser.sin_port = htons(6000);
ser.sin_addr.s_addr =inet_addr("127.0.0.1");
int res = bind(sockfd,(struct sockaddr *)&ser, sizeof(ser));
assert(res != -1);
listen(sockfd,5);
while(1)
{
int len = sizeof(cli);
int c = accept(sockfd,(struct sockaddr*)&cli,&len);
printf("accept success!\n");
assert(c != -1);
char buff[128] = {0};
recv(c,buff,127,0);
if(strncmp(buff,"end",3)== 0)
{
close(c);
break;
}
printf("recv::%s\n",buff);
send(c,"I Know",strlen("I Know"),0);
close(c);
}
close(sockfd);
}
2.客户端
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in ser,cli;
ser.sin_family = AF_INET;
ser.sin_port = htons(6000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = connect(sockfd,(struct sockaddr *)&ser,sizeof(ser));
assert(res != -1);
int key=1;
while(key)
{
char buff[128]={0};
fgets(buff,128,stdin);
send(sockfd,buff,strlen(buff),0);
printf("success!\n");
if(strncmp(buff,"end",3)==0)
{
key = 0;
}
recv(sockfd,buff,127,0);
printf("recv:: %s\n",buff);
}
close(sockfd);
}