unix网络编程代码(5)

继续贴《unix网络编程》上的示例代码。《unix网络编程》在第八章结束位置给出了一个使用select函数的TCP、UDP回射服务器程序,笔者把它实现了,现贴上代码:

服务端代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <strings.h>
  5 #include <sys/socket.h>
  6 #include <sys/types.h>
  7 #include <sys/wait.h>
  8 #include <arpa/inet.h>
  9 #include <signal.h>
 10 #include <errno.h>
 11 #include <netinet/in.h>
 12 
 13 #define SER_PORT 9374
 14 
 15 void handler (int signo);
 16 int maxfd (int fd1,int fd2);
 17 void str_echo (int connfd);
 18 ssize_t writen (int fd,void *vptr,size_t n);
 19 
 20 int main ()
 21 {
 22     int tcp_fd,udp_fd,connfd;
 23     int nready,maxfd1;
 24     fd_set rset;
 25     pid_t pid;
 26     ssize_t n;
 27     char recvline[4096];
 28     socklen_t clilen,serlen;
 29     socklen_t uclilen;
 30     struct sockaddr_in seraddr,tcp_cli,udp_cli;
 31     struct sigaction act,old;
 32     const int on = 1;
 33 
 34     bzero (&seraddr,sizeof (seraddr));
 35     bzero (&tcp_cli,sizeof (tcp_cli));
 36     bzero (&udp_cli,sizeof (udp_cli));
 37     bzero (&act,sizeof (act));
 38     bzero (&old,sizeof (old));
 39 
 40     /*for signal*/
 41     act.sa_flags = 0;
 42     act.sa_handler = handler;
 43     sigemptyset (&act.sa_mask);
 44 
 45     if ((sigaction (SIGCHLD,&act,&old)) < 0) {
 46         perror ("sigaction");
 47         exit (1);
 48     }
 49 
 50     /*for tcp connection*/
 51     if ((tcp_fd = socket (AF_INET,SOCK_STREAM,0)) < 0) {
 52         perror ("socket");
 53         exit (1);
 54     }
 55     if ((setsockopt (tcp_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof (on))) < 0) {
 56         perror ("setsockopt");
 57         exit (1);
 58     }
 59 
 60     seraddr.sin_family = AF_INET;
 61     seraddr.sin_port = htons (SER_PORT);
 62     seraddr.sin_addr.s_addr = htonl (INADDR_ANY);
 63 
 64 
 65     if ((bind (tcp_fd,(struct sockaddr *)&seraddr,sizeof (seraddr))) < 0) {
 66         perror ("bind");
 67         exit (1);
 68     }
 69 
 70     if ((listen (tcp_fd,20)) < 0) {
 71         perror ("listen");
 72         exit (1);
 73     }
 74 
 75     /*for udp connection*/
 76     if ((udp_fd = socket (AF_INET,SOCK_DGRAM,0)) < 0) {
 77         perror ("socket");
 78         exit (1);
 79     }
 80 
 81     bzero (&seraddr,sizeof (seraddr));
 82     seraddr.sin_family = AF_INET;
 83     seraddr.sin_addr.s_addr = htonl (INADDR_ANY);
 84     seraddr.sin_port = htons (SER_PORT);
 85 
 86     if ((bind (udp_fd,(struct sockaddr*) &seraddr,sizeof (seraddr))) < 0) {
 87         perror ("bind");
 88         exit (1);
 89     }
 90 
 91     /*select*/
 92     maxfd1 = maxfd (tcp_fd,udp_fd) + 1;
 93     FD_ZERO (&rset);
 94     while (1) {
 95         FD_SET (tcp_fd,&rset);
 96         FD_SET (udp_fd,&rset);
 97         if ((nready = select (maxfd1,&rset,NULL,NULL,NULL)) < 0) {
 98             if (errno = EINTR)
 99                 continue;
100             else {
101                 perror ("select");
102                 exit (1);
103             }
104         }
105 
106         if (FD_ISSET (tcp_fd,&rset)) {
107             clilen = sizeof (tcp_cli);
108             connfd = accept (tcp_fd,(struct sockaddr*)&tcp_cli,&clilen);
109             pid = fork ();
110 
111             if (pid < 0) {
112                 perror ("fork");
113                 exit (1);
114             }
115             else if (pid == 0) 
116                 close (connfd);
117             else {
118                 printf ("process %d created\n",getpid ());
119                 close (tcp_fd);
120                 /*communication with client*/
121                 str_echo (connfd);
122                 printf ("process %d exit\n",getpid ());
123                 exit (0);
124             }
125         }
126 
127         if (FD_ISSET (udp_fd,&rset)) {
128             uclilen = sizeof (udp_cli);
129             n = recvfrom (udp_fd,recvline,4096,0,(struct sockaddr*) &udp_cli,&uclilen);
130             sendto (udp_fd,recvline,n,0,(struct sockaddr*) &udp_cli,uclilen);
131         }
132     }
133 
134     return 0; 
135 }
136 
137 void handler (int signo)
138 {
139     pid_t chldpid;
140     while ((chldpid = waitpid (-1,NULL,WNOHANG)) > 0) {
141         printf ("child process %d terminated\n",chldpid);
142     } 
143 }
144 
145 int maxfd (int fd1,int fd2)
146 {
147     if (fd1 >= fd2)
148         return fd1;
149     else 
150         return fd2;
151 }
152 
153 void str_echo (int connfd)
154 {
155     ssize_t n;
156     char buf[4096];
157 again:
158     while ((n = read (connfd,buf,4096)) > 0)
159         writen (connfd,buf,n);
160 
161     if (n < 0 && errno == EINTR)
162         goto again;
163     else if (n < 0) {
164         perror ("write");
165         exit (1);
166     }
167 
168     printf ("str_echo end\n");
169 }
170 
171 ssize_t writen (int fd,void *vptr,size_t n)
172 {
173     size_t nleft;
174     ssize_t nwritten;
175     const char *ptr;
176 
177     ptr = vptr;
178     nleft = n;
179     while (nleft > 0) {
180         if ((nwritten = write (fd,ptr,nleft)) <= 0) {
181             /*nothing written or an error occured*/
182             if (nwritten < 0 && errno == EINTR) {
183             /*
184              *The  call  was interrupted by a signal before any data was read
185              *and call it again.
186              */
187                 nwritten = 0;
188             } else {
189             /*the call was interrupted by other signal,return -1*/
190                 return (-1);
191             }
192         }
193 
194         nleft -= nwritten;
195         ptr += nwritten;
196     }
197 
198     return (n);
199 }

 

使用UDP协议的客户端:

 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 }

 

使用TCP协议的客户端:

 1 #include "wrap.h"
 2      
 3 #define SER_PORT      9374
 4 
 5 void str_cli (FILE *fp,int connfd);
 6 
 7 int main ()
 8 {
 9     int sockfd;
10     char *ip = "127.0.0.1";
11     struct sockaddr_in seraddr;
12 
13     sockfd = Socket (AF_INET,SOCK_STREAM,0);
14 
15     seraddr.sin_family = AF_INET;
16     seraddr.sin_port = htons (SER_PORT);
17     inet_pton (AF_INET,ip,&seraddr.sin_addr);
18 
19     Connect (sockfd,&seraddr,sizeof (seraddr));
20     str_cli (stdin,sockfd);
21 
22     return 0;
23 }
24 
25 void str_cli (FILE *fp,int connfd)
26 {
27     int maxfpd1,stdineof;
28     fd_set rset;
29     char buf[MAXLINE];
30     int n;
31 
32     stdineof = 0;
33     while (1) {
34         if (stdineof == 0) 
35             FD_SET (fileno (fp),&rset);
36         FD_SET (connfd,&rset);
37         maxfpd1 = Max (fileno (fp),connfd) + 1;
38         select (maxfpd1,&rset,NULL,NULL,NULL);
39 
40         if (FD_ISSET (connfd,&rset)) {
41             if ((n = read (connfd,buf,MAXLINE)) == 0) {
42                 if (stdineof == 1) 
43                     return;
44                 else {
45                     printf ("str_cli:server terminated too early");
46                     exit (1);
47                 }
48             }
49             write (fileno (stdout),buf,n);
50         } 
51 
52         if (FD_ISSET (fileno (fp),&rset)) {
53             if ((n = read (fileno (fp),buf,MAXLINE)) == 0) {
54                 stdineof = 1;
55                 shutdown (connfd,SHUT_WR);
56                 FD_CLR (fileno (fp),&rset);
57                 continue;
58             }
59 
60             writen (connfd,buf,n);
61         }
62     }
63 }

其中,wrap.h以及一些包裹函数的实现,请见笔者博文《unix网络编程》(2)。

在服务端代码中:

1.建立了两个套接字,分别用于tcp、udp通信

2.两个套接字绑定于同一ip地址和端口(setsockopt实现)

3.捕捉SIGCHLD信号,回收子进程资源

4.使用select监听tcp的监听套接字,当tcp连接成功之后,建立子进程处理客户端信息;同时监听使用数据报协议的套接字

 

代码中有不完善的地方,还望多多指教。

转载于:https://www.cnblogs.com/zxy-2016/p/5199970.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值