由于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成员,后面就不多说了!!