linux下搭建能同时接收UDP和TCP连接的socket并发多线程服务器

由于UDP和TCP函数接口不同,所以服务器的处理线程需要能分清此时客户端的链接方式,这里通过传递简单一个pthread_arg.protocol变量来识别
==============================================================
//include.h
…………
…………省略若干头文件、参数、函数声明
…………
struct pthread_arg{  //供线程使用的参数
     char protocol;// protocol =='U'为udp连接 ; protocol == 'T'则为tcp连接;
     int fd;
     struct sockaddr_in sock;
};

==============================================================
//server.c

#include "include.h"

int main(int argc, char ** argv)
{
     struct sockaddr_in server_addr, client_addr;
     struct pthread_arg ptr_arg;//供线程使用的参数
     fd_set fdset;
     pthread_t pthid;
     int tcp_socketfd, tcp_connectfd, udp_connectfd, maxfd;
     int client_len;
     char local_port[32], local_ip[32];
     int reuse = 1;//进程结束后端口允许重用,否则在调试程序时得等系统回收端口,浪费时间
     void *retval;
// struct timeval timeout = { 3, 0};

//--------------------- TCP ----------------------------------------------------------
     if((tcp_socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
          printf("fail to socket!!\n");
          exit(-1);
     }
//  printf("socket success!!\n");
     setsockopt(tcp_socketfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));

     bzero(&server_addr, sizeof(server_addr));
     server_addr.sin_family = AF_INET;

     sprintf(local_ip, "%s", LOCAL_IP);
     server_addr.sin_addr.s_addr = inet_addr(local_ip);
     printf("[server ip = %s]\n", local_ip);

     sprintf(local_port, "%d", LOCAL_PORT);
     server_addr.sin_port = htons(atoi(local_port));
     printf("[server port = %s]\n", local_port);
    
     if(bind(tcp_socketfd,  (struct sockaddr *)&server_addr,  sizeof(server_addr)) < 0){
          perror("fail to bind!!");
          exit(-1);
     }
    
     if(listen(tcp_socketfd, 5) < 0){
          perror("fail to listen!!");
          exit(-1);
     }
//--------------------- UDP --------------------------------------------------------------------- 
     if((udp_connectfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
          perror("Error : udp fail to socket!!\n");
          exit(-1);
     }
     if(bind(udp_connectfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
          perror("Error : udp fail to bind!!\n");
          exit(-1);
     }
     maxfd = (tcp_connectfd > udp_connectfd ? tcp_connectfd : udp_connectfd);

     while(1){
          FD_ZERO(&fdset);
          FD_SET(tcp_socketfd, &fdset);
          FD_SET(udp_connectfd, &fdset);
          if(select(maxfd+1, &fdset, NULL, NULL, NULL)< 0){
               perror("Error: select error!!\n");
               exit(-1);
          }

          //tcp连接------------------------------- 
          //为每一个tcp客户端创建独立的处理线程,线程处理函数为deal_send_pth,参数为ptr_arg
          if(FD_ISSET(tcp_socketfd, &fdset)){
              //循环接受客户端的链接请求
               client_len = sizeof(client_addr);
               if((tcp_connectfd = accept(tcp_socketfd, (struct sockaddr *)&client_addr, (socklen_t *)&(client_len))) < 0){
                    perror("fail to accept!!");
                    return -1;
               }
              
               ptr_arg.protocol = 'T';
               ptr_arg.fd = tcp_connectfd;
               strcpy((char *)&ptr_arg.sock, (const char *)&client_addr);
               if(pthread_create(&pthid, NULL, deal_send_pth, (void *)&ptr_arg) < 0){
                    perror("fail to pthread_create!!");
                    return -1;
               }
               pthread_detach(pthid);//回收线程、非阻塞
          }


          //udp连接--------------------------------
          //为每一个udp客户端创建独立的处理线程,线程处理函数同样为deal_send_pth,参数为ptr_arg 
          if(FD_ISSET(udp_connectfd, &fdset)){
               ptr_arg.protocol = 'U';
               ptr_arg.fd = udp_connectfd;
               strcpy((char *)&ptr_arg.sock, (const char *)&client_addr);
               if(pthread_create(&pthid, NULL, deal_send_pth, (void *)&ptr_arg) < 0){
                    perror("fail to pthread_create!!");
                    return -1;
               }
               pthread_join(pthid, &retval);//回收线程、非阻塞
          }
     }

 return 0;
}
//deal_send_pth()中可以拿到pth_arg,判断下protocol成员,后面就不多说了!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值