環境:Linuxhtml
語言:C/C++服務器
通訊方式:UDPsocket
服務器端的步驟以下:
1. socket: 創建一個socket函數
2. bind: 將這個socket綁定在某個端口上(AF_INET)spa
3. recvfrom: 若是沒有客戶端發起請求,則會阻塞在這個函數裏.net
4. close: 通訊完成後關閉socketcode
客戶端的步驟以下:
1. socket: 創建一個socketserver
2. sendto: 向服務器的某個端口發起請求(AF_INET)htm
3. close: 通訊完成後關閉socketblog
基於UDP的接收和發送函數
int recvfrom(int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen);
int sendto(int sockfd, const void * buf, size_t len, int flags, const struct sockaddr * dest_addr, socklen_t addrlen);
UDP套接字不會保持鏈接狀態,每次傳輸數據都要添加目標地址信息,這至關於在郵寄包裹前填寫收件人地址。
recvfrom用於接收數據,sendto用於發送數據
recvfrom:
- sockfd:用於接收UDP數據的套接字;
- buf:保存接收數據的緩衝區地址;
- len:可接收的最大字節數(不能超過buf緩衝區的大小);
- flags:可選項參數,若沒有可傳遞0;
- src_addr:存有發送端地址信息的sockaddr結構體變量的地址;
- addrlen:保存參數 src_addr的結構體變量長度的變量地址值。
sendto:
- sockfd:用於傳輸UDP數據的套接字;
- buf:保存待傳輸數據的緩衝區地址;
- len:帶傳輸數據的長度(以字節計);
- flags:可選項參數,若沒有可傳遞0;
- dest_addr:存有目標地址信息的 sockaddr 結構體變量的地址;
- addrlen:傳遞給參數 dest_addr的地址值結構體變量的長度。
Server.cpp
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <unistd.h> 6 #include <errno.h> 7 #include <string.h> 8 #include <stdlib.h> 9 10 #define SERV_PORT 8000 11 12 int main() 13 { 14 /* sock_fd --- socket文件描述符 建立udp套接字*/ 15 int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 16 if(sock_fd < 0) 17 { 18 perror("socket"); 19 exit(1); 20 } 21 22 /* 將套接字和IP、端口綁定 */ 23 struct sockaddr_in addr_serv; 24 int len; 25 memset(&addr_serv, 0, sizeof(struct sockaddr_in)); //每一個字節都用0填充 26 addr_serv.sin_family = AF_INET; //使用IPV4地址 27 addr_serv.sin_port = htons(SERV_PORT); //端口 28 /* INADDR_ANY表示無論是哪一個網卡接收到數據,只要目的端口是SERV_PORT,就會被該應用程序接收到 */ 29 addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); //自動獲取IP地址 30 len = sizeof(addr_serv); 31 32 /* 綁定socket */ 33 if(bind(sock_fd, (struct sockaddr *)&addr_serv, sizeof(addr_serv)) < 0) 34 { 35 perror("bind error:"); 36 exit(1); 37 } 38 39 40 int recv_num; 41 int send_num; 42 char send_buf[20] = "i am server!"; 43 char recv_buf[20]; 44 struct sockaddr_in addr_client; 45 46 while(1) 47 { 48 printf("server wait:\n"); 49 50 recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_client, (socklen_t *)&len); 51 52 if(recv_num < 0) 53 { 54 perror("recvfrom error:"); 55 exit(1); 56 } 57 58 recv_buf[recv_num] = '\0'; 59 printf("server receive %d bytes: %s\n", recv_num, recv_buf); 60 61 send_num = sendto(sock_fd, send_buf, recv_num, 0, (struct sockaddr *)&addr_client, len); 62 63 if(send_num < 0) 64 { 65 perror("sendto error:"); 66 exit(1); 67 } 68 } 69 70 close(sock_fd); 71 72 return 0; 73 }
Client.cpp
1 #include <stdio.h> 2 #include <string.h> 3 #include <errno.h> 4 #include <stdlib.h> 5 #include <unistd.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <netinet/in.h> 9 #include <arpa/inet.h> 10 11 12 #define DEST_PORT 8000 13 #define DSET_IP_ADDRESS "127.0.0.1" 14 15 16 int main() 17 { 18 /* socket文件描述符 */ 19 int sock_fd; 20 21 /* 創建udp socket */ 22 sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 23 if(sock_fd < 0) 24 { 25 perror("socket"); 26 exit(1); 27 } 28 29 /* 設置address */ 30 struct sockaddr_in addr_serv; 31 int len; 32 memset(&addr_serv, 0, sizeof(addr_serv)); 33 addr_serv.sin_family = AF_INET; 34 addr_serv.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS); 35 addr_serv.sin_port = htons(DEST_PORT); 36 len = sizeof(addr_serv); 37 38 39 int send_num; 40 int recv_num; 41 char send_buf[20] = "hey, who are you?"; 42 char recv_buf[20]; 43 44 printf("client send: %s\n", send_buf); 45 46 send_num = sendto(sock_fd, send_buf, strlen(send_buf), 0, (struct sockaddr *)&addr_serv, len); 47 48 if(send_num < 0) 49 { 50 perror("sendto error:"); 51 exit(1); 52 } 53 54 recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_serv, (socklen_t *)&len); 55 56 if(recv_num < 0) 57 { 58 perror("recvfrom error:"); 59 exit(1); 60 } 61 62 recv_buf[recv_num] = '\0'; 63 printf("client receive %d bytes: %s\n", recv_num, recv_buf); 64 65 close(sock_fd); 66 67 return 0; 68 }
程序運行截圖:
client向服務器發送了「hey, who are you?」的字符串,server返回"i am server!"的字符串。
參考連接: