繼續貼《unix網絡編程》上的示例代碼。在上一篇帖子中的反射程序使用了tcp協議實現,此次使用udp協議實現。linux
server段代碼:編程
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 #include <sys/types.h> 8 #include <errno.h> 9 #include <signal.h> 10 11 #define SER_PORT 9374 12 13 void dg_echo (int sockfd,struct sockaddr* pcli,socklen_t clilen); 14 void recvform_int (int signo); 15 16 int main () 17 { 18 int sockfd; 19 struct sockaddr_in seraddr,cliaddr; 20 struct sigaction act; 21 if ((sockfd = socket (AF_INET,SOCK_DGRAM,0)) < 0) { 22 perror ("socket"); 23 exit (1); 24 } 25 bzero (&act,sizeof (act)); 26 bzero (&seraddr,sizeof (seraddr)); 27 bzero (&cliaddr,sizeof (cliaddr)); 28 seraddr.sin_family = AF_INET; 29 seraddr.sin_port = htons (SER_PORT); 30 seraddr.sin_addr.s_addr = htonl (INADDR_ANY); 31 32 if ((bind (sockfd,(struct sockaddr *)&seraddr,sizeof (seraddr))) < 0) { 33 perror ("bind"); 34 exit (1); 35 } 36 37 act.sa_handler = recvform_int; 38 sigemptyset (&act.sa_mask); 39 act.sa_flags = 0; 40 41 if ((sigaction (SIGINT,&act,NULL)) < 0) { 42 perror ("sigaction"); 43 exit (1); 44 } 45 46 dg_echo (sockfd,(struct sockaddr*) &cliaddr,sizeof (cliaddr)); 47 48 return 0; 49 } 50 51 void recvform_int (int signo) 52 { 53 printf ("terminated by user\n"); 54 exit (1); 55 } 56 57 void dg_echo (int sockfd,struct sockaddr* pcli,socklen_t clilen) 58 { 59 int n; 60 char recvline[4096]; 61 socklen_t len = clilen; 62 63 while (1) { 64 len = clilen; 65 n = recvfrom (sockfd,recvline,4096,0,pcli,&len); 66 sendto (sockfd,recvline,n,0,pcli,len); 67 } 68 } 69 70
client端代碼: 1 #include <stdlib.h>服務器
2 #include <stdio.h> 3 #include <unistd.h> 4 #include <errno.h> 5 #include <arpa/inet.h> 6 #include <netinet/in.h> 7 #include <sys/socket.h> 8 #include <sys/types.h> 9 #include <string.h> 10 11 #define SER_PORT 9374 12 13 void dg_cli (FILE *fp,int sockfd, 14 const struct sockaddr *pser, 15 socklen_t serlen); 16 17 int main () 18 { 19 int sockfd; 20 struct sockaddr_in seraddr; 21 char *ip = "127.0.0.1"; 22 23 if ((sockfd = socket (AF_INET,SOCK_DGRAM,0)) == -1) { 24 perror ("socket"); 25 exit (1); 26 } 27 28 bzero (&seraddr,sizeof (seraddr)); 29 seraddr.sin_family = AF_INET; 30 seraddr.sin_port = htons (SER_PORT); 31 inet_pton (AF_INET,ip,&seraddr.sin_addr); 32 33 dg_cli (stdin,sockfd,(struct sockaddr*)&seraddr,sizeof (seraddr)); 34 35 return 0; 36 } 37 38 39 void dg_cli (FILE *fp,int sockfd, 40 const struct sockaddr *pser, 41 socklen_t serlen) { 42 int n; 43 char sendline[4096]; 44 char recvline[4096];
45 if ((connect (sockfd,pser,serlen)) < 0) { 46 perror ("connect"); 47 exit (1); 48 } 49 50 while ((fgets (sendline,4096,fp)) != NULL) { 51 write (sockfd,sendline,strlen (sendline)); 52 n = read (sockfd,recvline,4096); 53 recvline[n] = '\0'; 54 printf ("%s\n",recvline); 55 } 56 }
在客戶端中,按下鍵盤ctrl+c輸入EOF,fgets函數會自動退出;在服務端中按下ctrl+c結束程序(由於設置捕捉了SIGINT信號)。網絡
在客戶端中使用了connect函數(是的,在udp協議中也能夠使用connect函數),《unix網絡編程》對於connect函數有以下總結:socket
咱們能夠說UDP客戶進程或者服務進程只在使用本身的UDP套接字與肯定的惟一對端進行通信,纔會調用connect。調用connect的一般是UDP客戶,不過某些網絡應用中的UDP服務器會與單個客戶長時間通訊(好比TFTP),這種狀況下,客戶和服務都有可能調用connect。在linux programmer`s manual手冊中,關於connect和udp是這麼說的:tcp
If the socket sockfd is of type SOCK_DGRAM, then addr is the address to
which datagrams are sent by default, and the only address from which
datagrams are received.函數
例如:connect (sockfd,(struct sockaddr*)addr,sizeof (addr));spa
若是sockfd是使用UDP的一個套接字,那麼addr所表示的地址就是使用sockfd文件描述符發送數據的默認地址(默認發送到addr所示的地址),以及使用sockfd可以接收到的數據的惟一來源。unix