1.TCP通信过程
TCP 是一个面向连接的,安全的,流式传输协议,这个协议是一个传输层协议。
(1)面向连接:是一个双向连接,通过三次握手完成,断开连接需要通过四次挥手完成;
(2)安全:tcp 通信过程中,会对发送的每一数据包都会进行校验,如果发现数据丢失,会自动重传;
(3)流式传输:发送端和接收端处理数据的速度,数据的量都可以不一致。
2.相关函数
(1)socket()创建socket对象
(2)connect() 请求连接
(3)send() 发送消息
(4)recv() 接收
(5)bind() 绑定ip和端口号
(6) listen() 监听是否有客户端的连接函数
(7)accept() 接收连接函数
(8)close() 通信结束关闭套接字函数
3.实现TCP通信的源码(含注释)
引入头文件:
#ifndef _NET_H#define _NET_H#include #include #include #include #include #include #include #include #endif
客户端:
#include #include "net.h"//编写一子函数,连接服务器端//参数1:IP地址//参数2:端口号//返回值:连接成功的socket对象,失败则返回-1int tcp_connect(const char * ip,int port){//1.创建TCPsocket对象socket//参数1:协议 IPV4 AF_INET//参数2:流式套接字//参数3:总是0int tcp_socket=socket(AF_INET,SOCK_STREAM,0);if(tcp_socket<0){perror("socket error");return -1;}printf("socket ok\n");//2.请求连接 connectstruct sockaddr_in server;server.sin_family=AF_INET;//协议server.sin_port=htons(port);server.sin_addr.s_addr=inet_addr(ip);//参数1:打开的socket对象//参数2:服务器端的地址信息//参数3:大小 if(connect(tcp_socket,(struct sockaddr *)&server,sizeof(server))<0){perror("connect error");return -1;}printf("connect ok\n");return tcp_socket;}//编写一子函数,实现tcp通信//参数1:连接好的socket对象//返回值:结束通信返回-1int tcp_com(int sockfd){char buf[50]={'\0'};fgets(buf,sizeof(buf),stdin);send(sockfd,buf,strlen(buf),0);return -1;}int main(int argc, const char *argv[]){if(argc<3){printf("input app ip port\n");return -1;}//TCP通信客户端//1.创建TCPsocket对象socket//2.请求连接 connect//3.发/收read/writesend/recv//4.关闭 close//1.请求连接tcp服务器int sockfd=tcp_connect(argv[1],atoi(argv[2]));//2.tcp通信返回-1,表示通信结束int n=tcp_com(sockfd);if(n<0){//关闭socket对象close(sockfd);}return 0;}
服务器:
#include #include "net.h"//编写一子函数,监听是否有人连接//参数1:IP地址 char * ip//参数2:端口号 int port//返回值:成功返回监听的socket对象,失败返回-1int tcp_server(const char * ip,int port){//1.创建tcpSocket对象socket()int tcp_socket=socket(AF_INET,SOCK_STREAM,0);if(tcp_socket<0){perror("socket error");return -1;}printf("socket ok\n");//2.绑定自己的IP地址和端口号 bind()struct sockaddr_in myAddr;memset(&myAddr,'\0',sizeof(myAddr));myAddr.sin_family=AF_INET;//协议myAddr.sin_port=htons(port);myAddr.sin_addr.s_addr=inet_addr(ip);if(bind(tcp_socket,(struct sockaddr *)&myAddr,sizeof(myAddr))<0){perror("bind error");return -1;}printf("bind ok\n");//3.监听(socket对象)是否有人连接 listen()if(listen(tcp_socket,5)<0){perror("listen error");return -1;}printf("listen ok\n");//4.返回监听的socket对象return tcp_socket;}//编写一子函数,进行TCP通信//参数:连接好的socket对象//返回值:通信结束返回-1,int tcp_com(int newfd){char buf[50]={'\0'};recv(newfd,buf,sizeof(buf),0);//接受第一条信息printf("%s\n",buf);return -1;}int main(int argc, const char *argv[]){if(argcIP地址//argv[2]----->port//1.获得监听的socket对象int listenfd=tcp_server(argv[1],atoi(argv[2]));//2.接受连接int newfd=0; //连接好的socket对象//参数1:监听好的socket对象//可以通过参数2和3获得客户端的信息(IP/PORT),若不关心,先设置为NULL//newfd=accept(listenfd,NULL,NULL);//想获得对方的IP地址和端口号struct sockaddr_in client;memset(&client,'\0',sizeof(client));int len=sizeof(client);//参数2:struct sockaddr *//参数3:&lennewfd=accept(listenfd,(struct sockaddr *)&client,&len);if(newfd主机字节序 ntohs(client.sin_port)//client.sin_addr.s_addr 网络字节序---->点分十进制的字符串inet_ntoa(client.sin_addr)printf("accept ok client ip=%s port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));//3.tcp通信//4.返回-1表示通信结束int n=tcp_com(newfd);//5.关闭socket对象if(n<0){close(newfd);}close(listenfd);return 0;}
// 以上内容为简单的TCP通信流程,其中的难点在于对函数参数的理解以及新生成的套接字newfd进行继续通信。读者在阅读时不妨设定这样一个场景:当我们在打电话通信时,第三个人给我们打电话(AB正在通信,C电话试图打通A),此时我们去进行三次握手后C和A进行正常通信,但是B可以保持接听状态,这就很好的模拟了TCP通信流程。
//关于三次握手、四次挥手的问题,比较复杂,读者可以查阅相关文档
———————————————————–我是分割线———————————————————end
写在文末:本文主要对TCP通信的流程进行了讲解,对其中的函数参数及返回值进行说明,同时设定一个简单的打电话模拟场景去帮助我们了解通信的流程。源代码已经给到,希望能对读者有所帮助。博主目前在华清远见西安中心学习
/*原创内容,有任何问题欢迎私信*/