UDP是具有数据边界的协议,传输中调用I/O函数的次数非常重要。输入函数的调用次数要和输出函数的调用次数完全一致,这样才能保证接受全部已发送的数据。
TCP套接字中需注册待传输数据的目标IP和端口,而UDP中无需注册。通过sendto函数传递数据的过程大约分为3个阶段:
第1阶段:向udp套接字注册目标IP和端口号。
第2阶段:传输数据。
第3阶段:删除udp套接字中注册的目标地址信息。
每次调用sendto函数时都会重复上述过程。这种未注册目标地址信息的套接字成为未连接套接字,反之,注册了目标地址的套接字称为连接connected套接字。UDP默认属于未连接套接字,创建已连接UDP套接字只需调用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> ", argv[0]); 16 exit(1); 17 } 18 int serverSock; 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_DGRAM, 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 37 puts("Server start..."); 38 while(1){ 39 clientAddrSize = sizeof(clientAddr); 40 strLen = recvfrom(serverSock, message, BUF_SIZE, 0, (struct sockaddr*) &clientAddr, &clientAddrSize); 41 sendto(serverSock, message, strLen, 0, (struct sockaddr*)&clientAddr, clientAddrSize); 42 } 43 close(serverSock); 44 puts("Server close..."); 45 return 0; 46 } 47 48 void error_handling(char * messages) 49 { 50 puts(messages); 51 exit(1); 52 }
客户端:
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 != 3) 14 { 15 printf("Usage : %s <IP> <port> ", argv[0]); 16 exit(1); 17 } 18 int sock; 19 struct sockaddr_in serv_addr, from_addr; 20 socklen_t addr_size; 21 char message[BUF_SIZE]; 22 int strLen; 23 24 sock = socket(PF_INET, SOCK_DGRAM, 0); 25 if(sock == -1) 26 error_handling("socket() error"); 27 28 memset(&serv_addr, 0, sizeof(serv_addr)); 29 serv_addr.sin_family = AF_INET; 30 serv_addr.sin_addr.s_addr = inet_addr(argv[1]); 31 serv_addr.sin_port = htons(atoi(argv[2])); 32 33 while(1){ 34 puts("Input message(Q to quit):"); 35 fgets(message, BUF_SIZE, stdin); 36 if(!strcmp(message, "q ") || !strcmp(message, "Q ")) 37 break; 38 sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_addr,sizeof(serv_addr)); 39 addr_size = sizeof(from_addr); 40 strLen = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&from_addr, &addr_size); 41 message[strLen]=0; 42 printf("Message from server: %s ", message); 43 } 44 close(sock); 45 return 0; 46 } 47 48 void error_handling(char * messages) 49 { 50 puts(messages); 51 exit(1); 52 }
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> ", argv[0]); 12 exit(1); 13 } 14 15 WSADATA wsa_data; 16 SOCKET server_sock; 17 SOCKADDR_IN server_addr, client_addr; 18 int sz_client_addr; 19 char message[BUF_SIZE]; 20 int str_len; 21 22 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) 23 ErrorHandling("WSAStartup() error."); 24 25 server_sock = socket(PF_INET, SOCK_DGRAM, 0); 26 if (server_sock == INVALID_SOCKET) 27 ErrorHandling("socket() error."); 28 29 memset(&server_addr, 0, sizeof(server_addr)); 30 server_addr.sin_family = AF_INET; 31 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 32 server_addr.sin_port = htons(atoi(argv[1])); 33 34 if (bind(server_sock, (SOCKADDR*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) 35 ErrorHandling("bind() error."); 36 printf("Server start... "); 37 while (true) 38 { 39 sz_client_addr = sizeof(client_addr); 40 str_len = recvfrom(server_sock, message, BUF_SIZE, 0, (SOCKADDR*)&client_addr, &sz_client_addr); 41 sendto(server_sock, message, str_len, 0, (SOCKADDR*)&client_addr, sizeof(message)); 42 } 43 closesocket(server_sock); 44 printf("Server end... "); 45 WSACleanup(); 46 return 0; 47 } 48 49 void ErrorHandling(char *message) { 50 fputs(message, stderr); 51 fputc(' ', stderr); 52 }
使用连接connected套接字的客户端:
针对UDP套接字调用connect函数并不意味着要与对方UDP套接字连接,这只是向UDP套接字注册目标IP和端口信息。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <winsock2.h> 5 6 #define BUF_SIZE 1024 7 void ErrorHandling(char *message); 8 9 int main(int argc, char* argv[]) { 10 if (argc != 3) { 11 printf("Usage : %s <IP> <port> ", argv[0]); 12 exit(1); 13 } 14 15 WSADATA wsa_data; 16 SOCKET h_socket; 17 SOCKADDR_IN server_addr; 18 19 char message[BUF_SIZE]; 20 int str_len; 21 22 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) 23 ErrorHandling("WSAStartup() error."); 24 25 h_socket = socket(PF_INET, SOCK_DGRAM, 0); 26 if (h_socket == INVALID_SOCKET) 27 ErrorHandling("socket() error."); 28 29 memset(&server_addr, 0, sizeof(server_addr)); 30 server_addr.sin_family = AF_INET; 31 server_addr.sin_addr.s_addr = inet_addr(argv[1]); 32 server_addr.sin_port = htons(atoi(argv[2])); 33 34 if (connect(h_socket, (SOCKADDR*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) 35 ErrorHandling("connect() error."); 36 37 while (true) 38 { 39 fputs("Insert message(q to quit): ", stdout); 40 fgets(message, sizeof(message), stdin); 41 if (!strcmp(message, "q ") || !strcmp(message, "Q ")) 42 break; 43 send(h_socket, message, strlen(message), 0); 44 str_len = recv(h_socket, message, sizeof(message) - 1, 0); 45 message[str_len] = 0; 46 printf("Message from server: %s", message); 47 } 48 closesocket(h_socket); 49 WSACleanup(); 50 return 0; 51 } 52 53 void ErrorHandling(char *message) { 54 fputs(message, stderr); 55 fputc(' ', stderr); 56 }
使用未连接套接字的客户端:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <winsock2.h> 5 6 #define BUF_SIZE 1024 7 void ErrorHandling(char *message); 8 9 int main(int argc, char* argv[]) { 10 if (argc != 3) { 11 printf("Usage : %s <IP> <port> ", argv[0]); 12 exit(1); 13 } 14 15 WSADATA wsa_data; 16 SOCKET h_socket; 17 SOCKADDR_IN server_addr, from_addr; 18 19 char message[BUF_SIZE]; 20 int str_len; 21 22 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) 23 ErrorHandling("WSAStartup() error."); 24 25 h_socket = socket(PF_INET, SOCK_DGRAM, 0); 26 if (h_socket == INVALID_SOCKET) 27 ErrorHandling("socket() error."); 28 29 memset(&server_addr, 0, sizeof(server_addr)); 30 server_addr.sin_family = AF_INET; 31 server_addr.sin_addr.s_addr = inet_addr(argv[1]); 32 server_addr.sin_port = htons(atoi(argv[2])); 33 34 while (true) 35 { 36 fputs("Insert message(q to quit): ", stdout); 37 fgets(message, sizeof(message), stdin); 38 if (!strcmp(message, "q ") || !strcmp(message, "Q ")) 39 break; 40 sendto(h_socket, message, strlen(message), 0, (SOCKADDR*)&server_addr, sizeof(server_addr)); 41 int sz_from_addr = sizeof(from_addr); 42 str_len = recvfrom(h_socket, message, BUF_SIZE, 0, (SOCKADDR*)&from_addr, &sz_from_addr); 43 message[str_len] = 0; 44 printf("Message from server: %s", message); 45 } 46 closesocket(h_socket); 47 WSACleanup(); 48 return 0; 49 } 50 51 void ErrorHandling(char *message) { 52 fputs(message, stderr); 53 fputc(' ', stderr); 54 }