unix网络编程代码(4)

继续贴《unix网络编程》上的示例代码。在上一篇帖子中的反射程序使用了tcp协议实现,这次使用udp协议实现。

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函数有如下总结:

我们可以说UDP客户进程或者服务进程只在使用自己的UDP套接字与确定的唯一对端进行通讯,才会调用connect。调用connect的通常是UDP客户,不过某些网络应用中的UDP服务器会与单个客户长时间通信(比如TFTP),这种情况下,客户和服务都有可能调用connect。在linux programmer`s manual手册中,关于connect和udp是这么说的:

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));

如果sockfd是使用UDP的一个套接字,那么addr所表示的地址就是使用sockfd文件描述符发送数据的默认地址(默认发送到addr所示的地址),以及使用sockfd能够接收到的数据的唯一来源。

 

posted @ 2016-02-18 16:20  纪老猴子  阅读(147)  评论(0编辑  收藏  举报