TCP程序的服务器端与客户端的流程图
例子:服务器端等待客户端连接,若连接成功,则用户可以通过客户端向服务器端发送任意字符串,服务器端在收到字符串后,输出相关信息,在把接受到的字符串重新发生给客户端。客户端收到后显示在屏幕上
服务器端:
#include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define SERVER_PORT 5555 int main() { int serverSocket; struct sockaddr_in server_addr; struct sockaddr_in clientAddr; int addr_len = sizeof(clientAddr); int client; char buffer[1024]; int iDataNum; //创建服务器端套接字,SOCK_STREAM指的是TCP通信,面向连接的字节流;SOCK_DGRAM是指UDP通信 if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) //创建服务器端套接字,返回值为套接字号 { perror("socket"); exit(1); } bzero(&server_addr, sizeof(server_addr)); // memset(server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; //AF_INET用来指定当前采用的协议是TCP/IP server_addr.sin_port = htons(SERVER_PORT); //htons()用于字节序的转换,表示将一个数值从主机字节序转换成网络字节序,保证数据的一致性 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//htons()函数是指16字节的转换,htonl()是32字节序转换 if (bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) //将地址信息与此前创建成功的套接字关联在一起 { perror("connect"); exit(1); } if (listen(serverSocket, 5) < 0) //服务套接字在指定端口监听,以被动的方式等待客户端连接,其中5为请求连接队列的最大长度 { perror("listen"); exit(1); } while (1) { //accept()函数主要是在指定的端口侦听,当客户端的连接请求到来时,维护并完成通信连接的建立,然后在这条链路上进行数据的收发 //第一个参数为当前服务套接字,第二个参数用于保存当前客户端的地址信息,第三个参数为客户端地址的长度 client = accept(serverSocket, (struct sockaddr *)&clientAddr, (socklen_t *)&addr_len); if (client < 0) { perror("accept"); continue; } iDataNum = read(client, buffer, 1024); buffer[iDataNum] = '\0'; if (iDataNum < 0) { perror("recv"); continue; } printf("\nRecv client data...\n"); printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr)); printf("Port is %d\n", htons(clientAddr.sin_port)); printf("Recv Data is %s, the data length is %d\n", buffer, iDataNum); write(client, buffer, iDataNum); } return 0; }
客户端:
#include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> int main() { int len; struct sockaddr_in serverAddr; int clientSocket; char sendbuf[200]; char recvbuf[200]; if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); return -1; } serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(5555); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //connect()函数帮助客户端向指定地址的服务器发起一条TCP连接,成功返回0;第一个参数为连接套接字,第二个为服务器端的地址信息和协议信息 if (connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { perror("connect"); exit(1); } printf("connect with destination host...\n"); while (1) { printf("Input your Word:>"); scanf("%s", sendbuf); //缺陷:不能传输带空格的句子 printf("\n"); if (strcmp(sendbuf, "quit") == 0) break; write(clientSocket, sendbuf, strlen(sendbuf)); len = read(clientSocket, recvbuf, 200); recvbuf[len] = '\0'; printf("recv data of my word is : %s\n", recvbuf); } close(clientSocket); return 0; }
注:有个小问题是为什么客户端不能循环输入?
UDP即无链接编程,和这个类似,一般用在P2P中,主要是创建socket的时候,要指定SOCK——DGRAM.
数据的收发调用sendto()和recvfrom().