TCP/IP协议(传输控制协议/互联网协议)叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的协议,如ICMP(互联网控制信息协议),FTP(文件传输协议),UDP(用户数据包协议),ARP(地址解析协议)等.TCP负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地。
套接字(socket):在网络中用来描述计算机中不同程序与其他计算机程序的通信方式.socket其实是一种特殊的IO借口,也是一种文件描述符。
套接字分为三类:
流式插座(SOCK_STREAM):流式套接字提供可靠,面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。
数据报套接字(SOCK_DGRAM):数据报套接字定义了一种无连接的服务,数据通过相互独立的保温进行传输,是无序的,并且不保证是可靠,无差错的。它使用的数据报协议是UDP。
原始插座:原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用复杂,主要用于一些协议的开发。
套接字由三个参数构成:IP地址,端口号,传输层协议。
这三个参数用以区分不同应用程序进程间的网络通信与连接。
套接字的数据结构:C语言进行套接字编程时,常会使用到sockaddr数据类型和指向sockaddr_in数据类型,用于保存套接字信息。
两种结构体分别表示如下:
struct sockaddr {//地址族2字节 无符号短sa_family;//存放地址和端口,14字节 char sa_data [14]; } 结构指向sockaddr_in {//地址族 短int sin_family;//端口号(使用网络字节序) 无符号短整型sin_port;//地址 struct in_addr sin_addr;//8字节数组,全为0,该字节数组的作用只是为了让两种数据结构大小相同而保留的空字节 无符号字符sin_zero [8] }
>之前对于sockaddr,大部分的情况下只是用于绑定、连接、recvfrom、sendto等函数的参数,指明地址信息,在一般编程中,并不对此结构体直接操作。而是用指向sockaddr_in来代替。
两种数据结构中,地址族都占2个字节,常见的地址族有:AF_INET, AF_INET6 AF_LOCAL。
这里要注意字节序的问题,最好使用以下函数来对端口和地址进行处理:
uint16_t htons (uint16_t host16bit) uint32_t htonl (uint32_t host32bit) uint16_t ntohs (uint16_t net16bit) uint32_t ntohs (uint32_t net32bit)将主机字节序改成网络字节序。
使用插座进行TCP通信时,经常使用的函数有:
下面是TCP通信的演示:
/* tcp套接字服务器端*/# include & lt; sys/stat.h> # include & lt; fcntl.h> # include & lt; errno.h> # include & lt; netdb.h> # include & lt; sys/types.h> # include & lt; sys/socket.h> # include & lt; netinet/in.h> # include & lt; arpa/inet.h> # include & lt; stdio.h> # include & lt; string.h> # include & lt; stdlib.h> # include & lt; unistd.h> #定义SERVER_PORT 5555/* 监听后,一直处于接受阻塞状态, 直到有客户端连接, 当客户端如数退出后,断开与客户端的连接 */int main () {//调用插座函数返回的文件描述符 int考察一下;//声明两个套接字指向sockaddr_in结构体变量,分别表示客户端和服务器 结构指向sockaddr_in server_addr; 结构指向sockaddr_in clientAddr; int addr_len=sizeof (clientAddr); int客户; 字符缓冲区[200]; int iDataNum;//套接字函数,失败返回1//int插座(int, int类型,int协议);//第一个参数表示使用的地址类型,一般都是ipv4, AF_INET//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM//第三个参数设置为0 如果((serverSocket=插座(AF_INET SOCK_STREAM 0)) & lt;0) { perror(“套接字”); 返回1; } bzero(及server_addr sizeof (server_addr));//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序 server_addr。sin_family=AF_INET; server_addr。sin_port=htons (SERVER_PORT);//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址 server_addr.sin_addr。s_addr=htonl (INADDR_ANY);//对于绑定,接受之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)//绑定三个参数:服务器端的套接字的文件描述符, 如果绑定(考察一下,(struct sockaddr *), server_addr, sizeof (server_addr)) & lt;0) { perror(“连接”); 返回1; }//设置服务器上的插座为监听状态 如果听(考察一下,5)& lt;0) { perror(“听”); 返回1; } 而(1) { printf("听>/* tcp套接字客户端*/# include & lt; sys/stat.h> # include & lt; fcntl.h> # include & lt; errno.h> # include & lt; netdb.h> # include & lt; sys/types.h> # include & lt; sys/socket.h> # include & lt; netinet/in.h> # include & lt; arpa/inet.h> # include & lt; stdio.h> # include & lt; string.h> # include & lt; stdlib.h> # include & lt; unistd.h> #定义SERVER_PORT 5555/* 连接到服务器后,会不停循环,等待输入, 输入退出后,断开与服务器的连接 */int main () {//客户端只需要一个套接字文件描述符,用于和服务器通信 int clientSocket;//描述服务器的插座 结构指向sockaddr_in serverAddr; char sendbuf [200]; char recvbuf [200]; int iDataNum; 如果((clientSocket=插座(AF_INET SOCK_STREAM 0)) & lt;0) { perror(“套接字”); 返回1; } serverAddr。sin_family=AF_INET; serverAddr。sin_port=htons (SERVER_PORT);//指定服务器端的ip,本地测试:127.0.0.1//inet_addr()函数,将点分十进制IP转换成网络字节序IP serverAddr.sin_addr。s_addr=inet_addr (127.0.0.1); 如果(连接(clientSocket (struct sockaddr *), serverAddr, sizeof (serverAddr)) & lt;0) { perror(“连接”); 返回1; } printf("联系目的地主机…\ n”); 而(1) { printf("输入你的世界:在"); scanf (“% s”, sendbuf); printf (" \ n "); 发送(clientSocket、sendbuf strlen (sendbuf), 0); 如果(strcmp (sendbuf,“戒烟”)==0) 打破; iDataNum=recv (clientSocket recvbuf 200,0); recvbuf [iDataNum]=' \ 0 '; printf (" recv数据我的世界:% s \ n”, recvbuf); } 关闭(clientSocket); 返回0; }如何基于C语言套接字编程实现TCP通信