一、TCP服务端
1、TCP服务端的默认函数调用顺序
- socket()创建套接字
- bind()分配套接字地址
- listen()等待请求连接状态
- accept()允许连接
- read()/write()数据交换
- close()断开连接
2、进入等待连接请求状态
只有调用了listen函数,客户端才能进入可发出连接请求的状态。即这时客户端才能调用connect()函数(若提前调用将发生错误)。
int listen(int sock, int backlog);
成功返回0,失败返回-1。sock指服务器端套接字,backlog指连接请求队列的长度,若为5,则队列长度为5,表示最多使5个连接请求进入队列。
3、受理客户端连接请求
int accept();
accept函数受理连接请求队列中待处理的客户端连接请求。函数调用成功时,accept函数内部将产生用于数据IO的套接字,并返回其文件描述符。需要强调的是,套接字是自动创建的,并自动与发起连接请求的客户端建立连接。
二、TCP客户端
1、TCP客户端的默认函数调用顺序
- socket()创建套接字
- connect()请求连接
- read/write数据交换
- close()断开连接
2、connect()
客户端调用connect函数后,发生以下情况之一才会返回(完成函数调用):
- 服务器端接收连接请求。
- 发生断网等异常情况而中断连接请求。
所谓的“接收连接”并不一位置服务器端调用accept函数,其实是服务器端把连接请求信息记录到等待队列。因此,connect函数返回后并不立即进行数据交换。
客户端的IP地址和端口是在调用connect函数时自动分配的。
三、回声服务端/客户端
1、linux
服务端:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <arpa/inet.h> 6 #include <sys/socket.h> 7 8 #define BUF_SIZE 1024 9 void error_handling(char * messages); 10 11 int main(int argc, char *argv[]) 12 { 13 if(argc != 2) 14 { 15 printf("Usage : %s <port>\n", argv[0]); 16 exit(1); 17 } 18 int serverSock, clientSock; 19 struct sockaddr_in serverAddr, clientAddr; 20 socklen_t clientAddrSize; 21 22 char message[BUF_SIZE]; 23 int strLen; 24 25 serverSock =socket(PF_INET, SOCK_STREAM, 0); 26 if(serverSock == -1) 27 error_handling("socket() error"); 28 29 memset(&serverAddr, 0, sizeof(serverAddr)); 30 serverAddr.sin_family = AF_INET; 31 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 32 serverAddr.sin_port = htons(atoi(argv[1])); 33 34 if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1) 35 error_handling("bind() error"); 36 if(listen(serverSock, 5) == -1) 37 error_handling("listen() error"); 38 39 puts("Server start..."); 40 clientAddrSize = sizeof(clientAddr); 41 for(int i = 0; i < 5; i++){ 42 clientSock = accept(serverSock, (struct sockaddr*) &clientAddr, &clientAddrSize); 43 if(clientSock == -1) 44 error_handling("accept() error"); 45 else 46 printf("Connected client %d\n", i+1); 47 while((strLen=read(clientSock, message, BUF_SIZE)) != 0){ 48 puts("echo"); 49 write(clientSock, message, strLen); 50 } 51 printf("Close client %d\n", i+1); 52 close(clientSock); 53 } 54 55 close(serverSock); 56 puts("Server close..."); 57 return 0; 58 } 59 60 void error_handling(char * messages) 61 { 62 puts(messages); 63 exit(1); 64 }
客户端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void error_handling(char * messages); int main(int argc, char *argv[]) { if(argc != 3) { printf("Usage : %s <IP> <port>\n", argv[0]); exit(1); } int sock; struct sockaddr_in serv_addr; char message[BUF_SIZE]; int strLen; sock = socket(PF_INET, SOCK_STREAM, 0); if(sock == -1) error_handling("socket() error"); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(argv[1]); serv_addr.sin_port = htons(atoi(argv[2])); if(connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) error_handling("connect() error"); else puts("Connected..."); while(1){ puts("Input message(Q to quit):"); fgets(message, BUF_SIZE, stdin); if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")) break; strLen=strlen(message); write(sock, message, strlen(message)); int recvLen = 0; while(recvLen < strLen){ int recvCnt = read(sock, &message[recvLen], BUF_SIZE-1); if(recvCnt == -1) error_handling("read() error"); recvLen+=recvCnt; } message[recvLen]=0; printf("Message from server: %s\n", message); } close(sock); return 0; } void error_handling(char * messages) { puts(messages); exit(1); }
2、windows
服务端:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <WinSock2.h> 4 5 #define BUF_SIZE 1024 6 void ErrorHandling(char *message); 7 8 int main(int argc, char *argv[]) 9 { 10 if (argc != 2) { 11 printf("Usage : %s <port>\n", argv[0]); 12 exit(1); 13 } 14 15 WSADATA wsaData; 16 SOCKET serverSock, clientSock; 17 SOCKADDR_IN serverAddr, clientAddr; 18 int szClientAddr; 19 char message[BUF_SIZE]; 20 int slen; 21 22 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 23 ErrorHandling("WSAStartup() error"); 24 25 serverSock = socket(PF_INET, SOCK_STREAM, 0); 26 if (serverSock == INVALID_SOCKET) 27 ErrorHandling("socket() error"); 28 memset(&serverAddr, 0, sizeof(serverAddr)); 29 serverAddr.sin_family = AF_INET; 30 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 31 serverAddr.sin_port = htons(atoi(argv[1])); 32 33 if (bind(serverSock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) 34 ErrorHandling("bind() error"); 35 36 if (listen(serverSock, 5) == SOCKET_ERROR) 37 ErrorHandling("listen() error"); 38 for (int i = 0; i < 5; ++i) { 39 szClientAddr = sizeof(clientAddr); 40 clientSock = accept(serverSock, (SOCKADDR*)&clientAddr, &szClientAddr); 41 if (clientSock == INVALID_SOCKET) 42 ErrorHandling("accept() error"); 43 else 44 printf("Connected client %d\n", i); 45 while ((slen =recv(clientSock, message, BUF_SIZE, 0)) != 0) 46 { 47 send(clientSock, message, slen, 0); 48 } 49 closesocket(clientSock); 50 printf("Closed client %d\n", i); 51 } 52 closesocket(serverSock); 53 WSACleanup(); 54 return 0; 55 } 56 57 void ErrorHandling(char *message) { 58 fputs(message, stderr); 59 fputc('\n', stderr); 60 }
客户端:
1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <winsock2.h> 6 7 #define BUF_SIZE 1024 8 void ErrorHandling(char *message); 9 10 int main(int argc, char* argv[]) { 11 if (argc != 3) { 12 printf("Usage : %s <IP> <port>\n", argv[0]); 13 exit(1); 14 } 15 16 WSADATA wsaData; 17 SOCKET sock; 18 SOCKADDR_IN serverAddr; 19 char message[BUF_SIZE]; 20 int sLen, recvLen; 21 22 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 23 ErrorHandling("WSAStartup() error"); 24 25 sock = socket(PF_INET, SOCK_STREAM, 0); 26 if (sock == INVALID_SOCKET) 27 ErrorHandling("socket() error"); 28 29 memset(&serverAddr, 0, sizeof(serverAddr)); 30 serverAddr.sin_family = AF_INET; 31 serverAddr.sin_addr.s_addr = inet_addr(argv[1]); 32 serverAddr.sin_port = htons(atoi(argv[2])); 33 34 if (connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) 35 ErrorHandling("connect() error"); 36 else 37 printf("Connected.......\n"); 38 while (1) 39 { 40 fputs("Input message(Q to quit):", stdout); 41 fgets(message, BUF_SIZE, stdin); 42 if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")) 43 break; 44 sLen = send(sock, message, strlen(message), 0); 45 recvLen = 0; 46 while (recvLen < sLen) { 47 int cnt = recv(sock, message, BUF_SIZE - 1, 0); 48 if (cnt == -1) 49 ErrorHandling("ercv() error"); 50 recvLen += cnt; 51 } 52 message[recvLen] = 0; 53 printf("Message from server: %s\n", message); 54 } 55 closesocket(sock); 56 WSACleanup(); 57 return 0; 58 } 59 60 void ErrorHandling(char *message) { 61 fputs(message, stderr); 62 fputc('\n', stderr); 63 }