目录
一、TCP基本概念
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。以下是TCP的一些基本概念:
-
面向连接:在数据传输之前,TCP在发送方和接收方之间建立一个连接。数据传输完成后,连接被释放。
-
可靠性:TCP提供可靠的数据传输,确保数据按照正确的顺序到达目的地,并且可以检测和纠正传输过程中出现的错误。
-
流控制:TCP使用滑动窗口协议进行流量控制,以确保发送端和接收端之间的数据传输速率合理,不会发生数据丢失或超负荷的情况。
-
拥塞控制:TCP通过控制数据包的发送速率来避免网络拥塞,以确保网络的稳定性和流畅性。
-
分段和重组:TCP在传输数据时会将数据分成较小的数据段进行传输,接收方收到数据后会重新组装成完整的数据。
-
端到端通信:TCP是端到端通信协议,意味着通信双方直接进行数据传输,而不需要经过中间设备的处理。

服务端:
socket():创建一个新的套接字。
bind(ip+port):将套接字绑定到指定的IP地址和端口号上,以便监听来自该地址和端口的连接请求。
listen():使套接字进入监听状态,等待客户端的连接请求。
accept():接受客户端的连接请求,建立连接。
recv():接收来自客户端的数据。
send():向客户端发送数据。
close():关闭套接字,结束通信。
客户端:
socket():创建一个新的套接字。
connect(ip+port):向服务端的指定IP地址和端口号发起连接请求。
send():向服务端发送数据。
recv():接收来自服务端的数据。
close():关闭套接字,结束通信。
二、ser服务器代码
TCP服务器程序,用于接受客户端的连接请求,并与客户端进行数据交换 。
cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
//创建套接字(打开文件,文件描述符) 套接字可以通过网络收发数据
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
exit(1);
}
struct sockaddr_in saddr,caddr;//服务器的ip端口
memset(&saddr,0,sizeof(saddr));//清空
saddr.sin_family=AF_INET;//填充
saddr.sin_port=htons(6000);//制定端口号为6000 小于1024是知名端口,1024~4096是保留的端口,4096以上是临时端口
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
//指定ip+端口
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//绑定,指定应用程序使用的ip及端口
if(res==-1)
{
printf("bind err\n");
exit(1);
}
res=listen(sockfd,5);
if(res==-1)
{
exit(1);
}
while(1)
{
int len=sizeof(caddr);//accept接受连接,如果没人连接,则阻塞
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
if(c<0)
{
break;
}
printf("accept c=%d\n",c);
pid_t pid=fork();
if(pid==0)
{
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);//接受连接,接收数据,会阻塞,也可以换成read()
if(n<=0)
{
break;
}
printf("recv:%s\n",buff);
send(c,"ok",2,0);//发送数据,也可以换成write()
}
printf("client close\n");
close(c);
exit(0);
}
close(c);
}
}
导入头文件:程序中导入了一些标准的头文件,包括stdio.h、stdlib.h、unistd.h、string.h、sys/socket.h、netinet/in.h、arpa/inet.h。
创建套接字:使用socket函数创建一个套接字,同样指定协议族(AF_INET,表示IPv4)、套接字类型(SOCK_STREAM,表示TCP流套接字)和协议参数(0)。
设置服务器地址:定义了两个结构体变量saddr和caddr,分别表示服务器和客户端地址。初始化saddr,并指定服务器的IP地址为"127.0.0.1",端口号为6000。
绑定地址:使用bind函数将套接字和服务器地址绑定在一起,指定服务器应用程序使用的IP地址和端口号。
监听连接:使用listen函数监听连接请求,指定最大连接数为5。
接受连接:通过accept函数接受客户端的连接请求。如果有客户端连接,则创建一个新的套接字描述符c,并接受连接。
多进程处理:在子进程中处理客户端的数据通信。在处理数据的循环中,接收客户端发送的数据,如果接收到数据则打印并发送"ok"回复客户端。如果接收到的数据长度小于等于0,表示客户端关闭连接,则跳出处理数据的循环,关闭客户端的套接字描述符c。
多进程处理:在父进程中关闭已接受的客户端连接。
三、cil客户端代码
客户端程序,用于连接到服务器并进行数据交换。
cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
//创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
exit(1);
}
struct sockaddr_in saddr;//指定服务器的ip和端口port
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//htons 转为网络字节序列 大端
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
printf("connect err\n");
exit(1);
}
char buff[128]={0};
printf("input:\n");
fgets(buff,128,stdin);
send(sockfd,buff,strlen(buff)-1,0);//可以用write
memset(buff,0,sizeof(buff));
recv(sockfd,buff,127,0);
printf("buff=%s\n",buff);
close(sockfd);
exit(0);
}
导入头文件:程序中导入了一些标准的头文件,包括stdio.h、stdlib.h、unistd.h、string.h、sys/socket.h、netinet/in.h、arpa/inet.h。
创建套接字:使用socket函数创建一个套接字,同样指定协议族(AF_INET,表示IPv4)、套接字类型(SOCK_STREAM,表示TCP流套接字)和协议参数(0)。
设置服务器地址:定义了一个结构体变量saddr,表示服务器地址。初始化saddr,并指定服务器的IP地址为"127.0.0.1",端口号为6000。
连接服务器:使用connect函数连接服务器,将套接字和服务器地址绑定在一起,连接到指定的服务器IP和端口。
发送和接收数据:提示用户输入数据,通过fgets函数读取用户输入的数据到缓冲区buff中。然后使用send函数将数据发送给服务器,发送的数据长度为输入长度减去换行符。接收服务器返回的数据,使用recv函数将数据读取到buff中。
打印数据:将接收到的数据打印输出。
关闭连接:使用close函数关闭套接字,结束客户端程序。
运行结果:
