一、TCP协议
(一)具体定义:TCP协议即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
(二)C/S模型:客户端 被动通讯方 数据提供者
服务器端 主动通讯方 数据获取者
(三)服务特点:
1.面向连接的传输;
2.端到端的通信;
3.高可靠性,确保传输数据的正确性,不出现丢失或乱序;
4.全双工方式传输;
5.采用字节流方式,即以字节为单位传输字节序列;
6.紧急数据传送功能。
(四)TCP服务器端编程流程
1.Int listenfd=scoket(); listenfd是一种套接字,文件描述符
listenfd只记录本端的地址信息
2.Bind() --->将listenfd与服务器的ip和选用的端口号进行绑定
服务器上IP地址固定,服器上的服务程序选的端口号也是固定的
3.Listen();---->启动监听,由内核监听listenfd代表的端口号,等待客户连接
listen程序不会阻塞,内核维护一个等待处理队列
4.Int c accept()----> 接受一个已完成连接过程的客户连接
C 文件描述符 代表与具体的客户端的连接,包含本端的和客户端的地址信息 地址对
通过C这个文件描述符与客户端交互
Recv()--->接收数据
Send()--->发送数据
Close(c)-->关闭连接
Close(listenfd)--->关闭服务器程序
代码实现如下:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include <signal.h>
int listenfd=-1;
void sigfun(int sign)
{
close(listenfd);
exit(0);
}
int main()
{
signal(SIGINT,sigfun);
// IPV4协议族 具体协议TCP
listenfd=socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd!=-1);
//服务器端地址的表示 struct sockaddr_in
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;//地址族
ser.sin_addr.s_addr=inet_addr("127.0.0.1");//ip地址
ser.sin_port=htons(6000);
int res=bind(listenfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res!=-1);//1.ip地址出错 2.端口号被占用或者无权限
listen(listenfd,5);//size=5指定内核维护已经完成链接但是没有被服务器处理的客户端的个数 size+1
while(1)//循环获取已完成链接的客户端
{
int clilen=sizeof(cli);//c代表与具体客户链接的文件描述符
int c =accept(listenfd,(struct sockaddr*)&cli,&clilen);
assert(c!=-1);
//循环与客户端交互 收发数据
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n<=0)
{
printf("one client unlink\n");
close(c);
break;
}
//业务逻辑处理
printf("%d: %s\n",c,buff);
send(c,"OK",2,0);
}
}
close(listenfd);
}
(五)TCP客户端编程流程
1.Int sockfd= socket();----->创建用户TCP通讯的文件描述符
2.Bind();----->可选 一般由系统自动探测客户端的IP地址,默认选择可用的端口号
3.Connect();---->主动发起连接 客户端必须知道服务器的IP地址以及使用的端口号
4.Recv()--->接收数据
5.Send()--->发送数据
6.Close(c)-->关闭连接
代码实现:
# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/in.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
// bind();
struct sockaddr_in ser;
memset(&ser,0,sizeof(ser));
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);
while(1)
{
printf("please input: ");
char buff[128]={0};
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
if(strncmp(buff,"goodbye",8)==0)
{
close(sockfd);
break;
}
send(sockfd,buff,strlen(buff),0);
char recvbuff[128]={0};
int n=recv(sockfd,recvbuff,127,0);
if(n<=0)
{
close(sockfd);
break;
}
printf("client recv data: %s\n",recvbuff);
}
}
以上的程序只是简单实现了客户端与服务器端的通讯,还存在一些没有解决的问题,还需再改进。