• 使用select函数


    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    
    const int maxline = 4096;
    
    size_t writen(int fd, const void *vptr, size_t n) {
            size_t nleft;
            size_t nwritten;
            const char *ptr;
    
            ptr=vptr;
            nleft=n;
            while(nleft>0) {
                    if((nwritten=write(fd, ptr, nleft))<=0) {
                            if(nwritten<0 && errno==EINTR)
                                    nwritten=0;
                            else
                                    return -1;
                    }
                    nleft-=nwritten;
                    ptr+=nwritten;
            }
            return n;
    }
    
    void str_echo(int sockfd) {
    	size_t n;
    	char buff[maxline];
    
    again:
    	while((n=read(sockfd, buff, maxline))>0) {
    		if(writen(sockfd, buff, n)!=n) {
    			fprintf(stderr, "writen error!\n");
    		}
    	}
    	if(n<0 && errno==EINTR)
    		goto again;
    	else if(n<0) {
    		fprintf(stderr, "read error\n");
    		exit(-1);
    	}
    }
    
    void sig_chld(int signo) {
    	pid_t pid;
    	int stat;
    	
    	while((pid=waitpid(-1, &stat, WNOHANG))>0) {
    		printf("child %d terminated\n", pid);
    	}
    	return;
    }
    
    int main(int argc, char **argv) {
    	int listenfd, connfd, udpfd, nready, maxfdp1, n;
    	pid_t childpid;
    	fd_set rset;
    	socklen_t len;
    	const int on=1;
    	struct sockaddr_in servaddr, cliaddr;
    	char mesg[maxline], errbuff[maxline];
    
    	if((listenfd=socket(AF_INET, SOCK_STREAM, 0))<0) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "socket error: %s\n", errbuff);
    		exit(-1);
    	}
    	
    	memset(&servaddr, 0, sizeof(servaddr));
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    	servaddr.sin_port = htons(9999);
    
    	if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))==-1) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "setsockopt error: %s\n", errbuff);
    		exit(-1);
    	}
    
    	if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "tcp bind error: %s\n", errbuff);
    		exit(-1);
    	}
    
    	if(listen(listenfd, 1024)<0) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "listen error: %s\n", errbuff);
    		exit(-1);
    	}
    
    	if((udpfd=socket(AF_INET, SOCK_DGRAM, 0))<0) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "socket error: %s\n", errbuff);
    		exit(-1);
    	}
    
    	memset(&servaddr, 0, sizeof(servaddr));
    	servaddr.sin_family=AF_INET;
    	servaddr.sin_port=htons(9999);
    	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    
    	if(bind(udpfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) {
    		strerror_r(errno, errbuff, maxline);
    		fprintf(stderr, "udp bind error: %s\n", errbuff);
    		exit(-1);
    	}
    
    	signal(SIGCHLD, sig_chld);
    	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;
    			else {
    				fprintf(stderr, "select error\n");
    				exit(-1);
    			}
    		}
    
    		if(FD_ISSET(listenfd, &rset)) {
    			len=sizeof(cliaddr);
    			if((connfd=accept(listenfd, (struct sockaddr *)&cliaddr, &len))<0) {
    				strerror_r(errno, errbuff, maxline);
    				fprintf(stderr, "accept error: %s\n", errbuff);
    				exit(-1);
    			}
    			printf("connection from %s, port %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, mesg, sizeof(mesg)), ntohs(cliaddr.sin_port));
    			if((childpid=fork())<0) {
    				strerror_r(errno, errbuff, maxline);
    				fprintf(stderr, "fork error: %s\n", errbuff);
    				exit(-1);
    			} else if(childpid == 0) {
    				printf("ppid: %d\n", getppid());
    				if(close(listenfd)<0) {
    					strerror_r(errno, errbuff, maxline);
    					fprintf(stderr, "child pid close listenfd error: %s\n", errbuff);
    					exit(-1);
    				}
    				str_echo(connfd);
    				exit(0);
    			} else {
    				printf("childpid: %d\n", childpid);
    				if(close(connfd)<0) {
    					strerror_r(errno, errbuff, maxline);
    					fprintf(stderr, "parent pid close connfd error: %s\n", errbuff);
    					exit(-1);
    				}
    			}
    		}
    
    		if(FD_ISSET(udpfd, &rset)) {
    			len=sizeof(cliaddr);
    			if((n=recvfrom(udpfd, mesg, maxline, 0, (struct sockaddr*)&cliaddr, &len))<0) {
    				strerror_r(errno, errbuff, maxline);
    				fprintf(stderr, "recvfrom error: %s\n", errbuff);
    				exit(-1);
    			}
    			printf("client ip: %s, client port: %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, errbuff, sizeof(errbuff)), ntohs(cliaddr.sin_port));
    
    			if(sendto(udpfd, mesg, n, 0, (struct sockaddr*)&cliaddr, len)<0) {
    				strerror_r(errno, errbuff, maxline);
    				fprintf(stderr, "sendto error: %s\n", errbuff);
    				exit(-1);
    			}
    		}
    	}
    	return 0;
    }	
    

      

  • 相关阅读:
    java 中静态变量和实例变量之间的区别
    java 中final 引用不可变,但是引用还是可以发生变化的
    java中char和Unicode之间的关系
    java 中终止内层循环的方法
    ssh 公钥免密码登陆
    关于Python 中unicode 转码的问题
    Python中Unicode码和非Unicode码引起的错误与格式转换
    第一次写博客,怎么写?
    zookeeper实现主-从结构的一般原理
    Python中Tuple的词源有趣探索
  • 原文地址:https://www.cnblogs.com/donggongdechen/p/16741174.html
Copyright © 2020-2023  润新知