同时使用tcp和udp回射服务器

同时使用select函数的tcp和udp回射服务器:

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
#define MAXLINE     1024
#define SERV_PORT   29988   //server使用的本地端口
#define LISTENQ     100     //listen侦听队列最大数
typedef struct sockaddr SA;

void sig_chld(int signo) {
    pid_t pid;
    int stat;
    //使用waitpid回收子进程
    while((pid=waitpid(-1,&stat,WNOHANG))>0){
        cout << "child " << pid << " terminated." << endl;
    }
    return ;
}
void str_echo(int sockfd) {
    ssize_t n;
    char buf[MAXLINE];
    again:
    while((n=read(sockfd,buf,MAXLINE))>0){
        write(sockfd,buf,n);
    }
    //如果errno为EINTR,表示被信号中断的系统调用,可以重入,应该重新调用
    if(n<0 && errno==EINTR){
        goto again;
    } else {
        cout << "str_echo read error." << endl;
        exit(-1);
    }
}
int main(int argc , char** argv) {
    int listenfd,connfd,udpfd,nready,maxfdp1;
    char mesg[MAXLINE];
    pid_t childpid;
    fd_set rset;
    ssize_t n;
    socklen_t len;
    const int on = 1;
    struct sockaddr_in cliaddr,servaddr;
    void sig_chld(int);

    //创建TCP本地套接字,指定端口,地址任意选取本地接口
    listenfd = socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_addr.s_addr = htonl(0);
    servaddr.sin_port=htons(SERV_PORT);
    //设置套接字端口可以重入
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    //绑定一个本地套接字地址
    bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
    //侦听本地套接字,最大排队数量为LISTENQ
    listen(listenfd,LISTENQ);

    //创建本地UDP套接字
    udpfd = socket(AF_INET,SOCK_DGRAM,0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=htonl(0);
    servaddr.sin_port = htons(SERV_PORT);
    //绑定一个本地套接字地址
    bind(udpfd,(SA*)&servaddr,sizeof(servaddr));

    //注册信号SIGCHLD,回收fork子进程
    signal(SIGCHLD,sig_chld);

    FD_ZERO(&rset);
    maxfdp1 = max(listenfd,udpfd) +1;

    for(;;){
        //添加侦听套接字listenfd和本地udp套接字到select可读集合
        FD_SET(listenfd,&rset);
        FD_SET(udpfd,&rset);
        //使用select判断是否可以读
        if((nready = select(maxfdp1,&rset,NULL,NULL,NULL)<0)){
            if(errno == EINTR){
                continue;
            } else {
                cout << "select error ." << endl;
                exit(-1);
            }
        }
        //检测listenfd
        if(FD_ISSET(listenfd,&rset)){
            len = sizeof(cliaddr);
            connfd = accept(listenfd,(SA*)&cliaddr,&len);
            //创建子进程,实现并发服务器
            if((childpid=fork())==0){
                close(listenfd);
                str_echo(connfd);
                exit(0);
            }
            close(connfd);
        }
        //检测udpfd
        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);
        }
    }
    return 0;
}       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值