使用select函数的TCP和UDP回射服务器程序

来源:互联网 发布:sql select 多张表 编辑:程序博客网 时间:2024/05/29 12:14

服务器程序


/* include udpservselect01 */#include"unp.h"intmain(int argc, char **argv){intlistenfd, connfd, udpfd, nready, maxfdp1;charmesg[MAXLINE];pid_tchildpid;fd_setrset;ssize_tn;socklen_tlen;const inton = 1;struct sockaddr_incliaddr, servaddr;voidsig_chld(int);/* 4create listening TCP socket */listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family      = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port        = htons(SERV_PORT);Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);/* 4create UDP socket */udpfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family      = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port        = htons(SERV_PORT);Bind(udpfd, (SA *) &servaddr, sizeof(servaddr));/* end udpservselect01 *//* include udpservselect02 */Signal(SIGCHLD, sig_chld);/* must call waitpid() */FD_ZERO(&rset);maxfdp1 = max(listenfd, udpfd) + 1;for ( ; ; ) {FD_SET(listenfd, &rset);FD_SET(udpfd, &rset);if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {if (errno == EINTR)continue;/* back to for() */elseerr_sys("select error");}if (FD_ISSET(listenfd, &rset)) {len = sizeof(cliaddr);connfd = Accept(listenfd, (SA *) &cliaddr, &len);if ( (childpid = Fork()) == 0) {/* child process */Close(listenfd);/* close listening socket */str_echo(connfd);/* process the request */exit(0);}Close(connfd);/* parent closes connected socket */}if (FD_ISSET(udpfd, &rset)) {len = sizeof(cliaddr);n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA *) &cliaddr, &len);Sendto(udpfd, mesg, n, 0, (SA *) &cliaddr, len);}}}/* end udpservselect02 */


创建TCP套接字

  • 17~28 创建一个监听套接字并捆绑服务器到总所周知的端口,设置 SO_REUSEADDR套接字选项防止该端口上已有连接存在。

创建UDP套接字

  • 30~38 还创建了一个UDP套接字捆绑于TCP套接字相同的端口,设置 SO_REUSEADDR套接字选项,因为TCP端口是独立于UDP端口的。

给SIGCHLD建立信号处理程序

  • 42 因为TCP连接将由某个子程序处理。给出这个信号处理函数见下面。

准备调用select

  • 44~45 我们给select初始化一个描述符集,并计算出我们等待的两个描述符的较大者。

调用select

  • 47~54 我们调用select只是为了等待监听TCP套接字的可读条件或UDP套接字的可读条件。 既然我们的sig_chld信号处理函数可能中断我们对select的调用,我们于是需要处理EINTR错误。

处理新的客户端连接

  • 56-66 当监听的TCP套接字可读时,我们accept一个新的客户连接,fork一个子程序,并在子程序进程中调用str_echo函数。

处理数据报的到达

  • 68~74 如果UDP套接字可读,那么已有一个数据报到达。我们使用recvfrom读入它,再使用sendto把它发回客户端。

客户端程序(tcp和udp)


TCP客户端程序
#include"unp.h"intmain(int argc, char **argv){intsockfd;struct sockaddr_inservaddr;if (argc != 2)err_quit("usage: tcpcli <IPaddress>");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));str_cli(stdin, sockfd);/* do it all */exit(0);}



UDP客户端程序
#include"unp.h"intmain(int argc, char **argv){intsockfd;struct sockaddr_inservaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));exit(0);}

信号处理程序


#include"unp.h"voidsig_chld(int signo){pid_tpid;intstat;while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated\n", pid);return;}


UDP的回射服务器程序:dg_echo函数


#include <unp.h>void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen){int n;socklen_tlen;char mesg[MAXLINE];for(;;){len = clilen;n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);Sendto(sockfd, mesg, n, 0, pcliaddr, len);}}


UDP的回射客户程序:dg_cli函数


#include <unp.h>void dg_cli(FILE *fp, int sockfd, const SA* pservaddr, socklen_t servlen){int n;charsendline[MAXLINE], recvline[MAXLINE+1];while(Fgets(sendline, MAXLINE, fp) != NULL){Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);recvline[n] = '\0';Fputs(recvline, stdout);}}





原创粉丝点击