IO复用高级应用:同时处理TCP和UDP服务

一个socket只能与一个socket地址绑定即一个socket只能监听一个端口,服务器如果要同时监听多个端口就必须创建多个socket,若在同一个端口监听多个服务也要创建多个socket绑定到这个端口上。现在服务器监听一个端口上的TCP和UDP请求,并将发送来的数据回射到客户端。
服务端程序:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <assert.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <sys/epoll.h> 
#include <pthread.h> 
   
#define MAX_EVENT_NUMBER 1024 //最大事件数目 
#define TCP_BUFFER_SIZE 512//TCP缓冲区 
#define UDP_BUFFER_SIZE 1024//UDP缓冲区 
   
int setnonblocking( int fd ) //设置为非阻塞描述符 
     int old_option = fcntl( fd, F_GETFL ); 
     int new_option = old_option | O_NONBLOCK; 
     fcntl( fd, F_SETFL, new_option ); 
     return old_option; 
   
void addfd( int epollfd, int fd ) //注册事件 
     epoll_event event; 
     event.data.fd = fd; 
     //event.events = EPOLLIN | EPOLLET; 
     event.events = EPOLLIN; //可读事件 
     epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 
     setnonblocking( fd ); 
   
int main( int argc, char * argv[] ) 
     if ( argc <= 2 ) 
    
         printf ( "usage: %s ip_address port_number\n" , basename( argv[0] ) ); 
         return 1; 
    
     const char * ip = argv[1]; 
     int port = atoi ( argv[2] ); 
   
     int ret = 0; 
     struct sockaddr_in address; //绑定TCP端口 
     bzero( &address, sizeof ( address ) ); 
     address.sin_family = AF_INET; 
     inet_pton( AF_INET, ip, &address.sin_addr ); 
     address.sin_port = htons( port ); 
   
     int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 
     assert ( listenfd >= 0 ); 
   
     ret = bind( listenfd, ( struct sockaddr* )&address, sizeof ( address ) ); 
     assert ( ret != -1 ); 
   
     ret = listen( listenfd, 5 ); 
     assert ( ret != -1 ); 
   
     bzero( &address, sizeof ( address ) ); //绑定UDP端口 
     address.sin_family = AF_INET; 
     inet_pton( AF_INET, ip, &address.sin_addr ); 
     address.sin_port = htons( port ); 
     int udpfd = socket( PF_INET, SOCK_DGRAM, 0 ); 
     assert ( udpfd >= 0 ); 
   
     ret = bind( udpfd, ( struct sockaddr* )&address, sizeof ( address ) ); 
     assert ( ret != -1 ); 
   
     epoll_event events[ MAX_EVENT_NUMBER ]; 
     int epollfd = epoll_create( 5 ); 
     assert ( epollfd != -1 ); 
     addfd( epollfd, listenfd ); //TCP端口注册事件 
     addfd( epollfd, udpfd ); //UDP端口注册事件 
   
     while ( 1 ) 
    
         int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); //无限期等待事件发生 
         if ( number < 0 ) 
        
             printf ( "epoll failure\n" ); 
             break
        
       
         for ( int i = 0; i < number; i++ ) //EPOLL就绪事件 
        
             int sockfd = events[i].data.fd; 
             if ( sockfd == listenfd ) //监听端口监听TCP连接事件 
            
                 struct sockaddr_in client_address; 
                 socklen_t client_addrlength = sizeof ( client_address ); 
                 int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 
                 addfd( epollfd, connfd ); 
            
             else if ( sockfd == udpfd ) //UDP连接 
            
                 char buf[ UDP_BUFFER_SIZE ]; 
                 memset ( buf, '\0' , UDP_BUFFER_SIZE ); 
                 struct sockaddr_in client_address; 
                 socklen_t client_addrlength = sizeof ( client_address ); //客户端地址 
         //UDP专用接收数据 
                 ret = recvfrom( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, &client_addrlength ); 
                 if ( ret > 0 ) 
                 { //UDP专用发送数据(回射数据) 
                     sendto( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, client_addrlength ); 
                
            
             else if ( events[i].events & EPOLLIN ) //TCP连接 
            
                 char buf[ TCP_BUFFER_SIZE ]; 
                 while ( 1 ) 
                
                     memset ( buf, '\0' , TCP_BUFFER_SIZE ); 
                     ret = recv( sockfd, buf, TCP_BUFFER_SIZE-1, 0 ); 
                     if ( ret < 0 ) 
                    
                         if ( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) //非阻塞出现这种errrno是读取数据完毕 
                        
                             break
                        
                         close( sockfd ); 
                         break
                    
                     else if ( ret == 0 ) //关闭连接 
                    
                         close( sockfd ); 
                    
                     else 
                    
                         send( sockfd, buf, ret, 0 ); //回射数据 
                    
                
            
             else 
            
                 printf ( "something else happened \n" ); 
            
        
    
   
     close( listenfd ); 
     return 0; 
}

 

 
客户端程序:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<sys/socket.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#include<assert.h> 
#include<stdio.h> 
#include<unistd.h> 
#include<string.h> 
#include<stdlib.h> 
#include<iostream> 
#define BUF_SIZE 1024 
using namespace std; 
int main( int argc, char * argv[]){ 
     if (argc<=2){ 
         cout<< "argc<=2" <<endl; 
         return 1; 
    
     const char * ip=argv[1]; 
     int port= atoi (argv[2]); 
     struct sockaddr_in server_address; 
     bzero(&server_address, sizeof (server_address)); 
     server_address.sin_family=AF_INET; 
     inet_pton(AF_INET,ip,&server_address.sin_addr); 
     server_address.sin_port=htons(port); 
     int sockfd=socket(PF_INET,SOCK_STREAM,0); 
     int sockudp=socket(PF_INET,SOCK_DGRAM,0); 
     assert (sockfd>=0); 
     if (connect(sockfd,( struct sockaddr*)&server_address, sizeof (server_address))<0){ //TCP数据发送与接收 
         cout<< "connect error" <<endl; 
         return 1; 
    
     else
         const char * tcp= "this is TCP data\n"
         send(sockfd,tcp, strlen (tcp),0); 
         char buf[BUF_SIZE]; 
         int ret=recv(sockfd,buf,BUF_SIZE-1,0); 
         if (ret<0){ 
             cout<< "recv tcp error" <<endl; 
        
         else
             buf[ret+1]= '\0'
             cout<<ret<< " " <<buf<<endl; 
        
    
     if (connect(sockudp,( struct sockaddr*)&server_address, sizeof (server_address))<0){ //UDP数据发送与接收
         cout<< "connect error" <<endl; 
         return 1; 
    
     else
         const char * udp= "this is UDP data\n"
         send(sockudp,udp, strlen (udp),0); 
         char buf[BUF_SIZE]; 
         int ret=recv(sockudp,buf,BUF_SIZE-1,0); 
         if (ret<0){ 
             cout<< "recv udp error" <<endl; 
        
         else
             buf[ret+1]= '\0'
             cout<<ret<< " " <<buf<<endl; 
        
    
     close(sockfd); 
     return 0; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值