同時使用tcp和udp回射伺服器
阿新 • • 發佈:2019-01-22
同時使用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;
}