linux C TCP UDP server 接收多个客户端同时连接的多线程

weixin_30072103 2018-07-13 10:00:38
我想做一个的TCP UDP server端,实现这样一个功能:每当一个客户端连接过来时,创建一个单独的线程去处理这个客户端。
现在测试发现,当多个TCP客户端连接进来的时候,只会保留最新的一个客户端线程通信,先连接进来的客户端线程都没在运行也无法发送数据?怎么回事?本人小白,请多指教。以下是代码:

#include ..一些头文件,省略。
#define LOCAL_IP "192.168.1.66"
#define LOCAL_PORT 8888
struct pthread_arg//供线程使用的参数
{
char protocol;// protocol =='U'为udp连接 ; protocol == 'T'则为tcp连接;
int fd;
struct sockaddr_in sock;
int num;
};

static void *deal_send_pth(void *arg)
{
struct pthread_arg *r=( struct pthread_arg *)arg;
printf("pth%d running...\n",r->num);

}

main()
{
int i;
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;

//--------------------- 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("[tcp 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 ---------------------------------------------------------------------
server_addr.sin_port = htons(atoi(local_port));
printf("[udp server port = %s]\n", local_port);

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)
{
struct sockaddr_in client_addr;
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))
{
printf("----------pass 2 -------------\n");
sleep(1);
//循环接受客户端的链接请求
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;
memcpy((char *)&ptr_arg.sock, (const char *)&client_addr,sizeof(struct sockaddr_in));
ptr_arg.num = i;
if(pthread_create(&pthid, NULL, deal_send_pth, (void *)&ptr_arg) < 0)
{
perror("fail to pthread_create!!");
return -1;
}
pthread_detach(pthid);//回收线程、非阻塞
i++;
}
}
}
...全文
1048 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
同IP同port两个程序同时接收可以实现么?
weixin_30072103 2018-07-16
  • 打赏
  • 举报
回复
引用 2 楼 sghcpt 的回复:
楼主:应该是下面的代码由问题吧?
ptr_arg.protocol = 'T';
ptr_arg.fd = tcp_connectfd;
memcpy((char *)&ptr_arg.sock, (const char *)&client_addr,sizeof(struct sockaddr_in));
ptr_arg.num = i;
if(pthread_create(&pthid, NULL, deal_send_pth, (void *)&ptr_arg) < 0)

其中ptr_arg变量,每次接受到一个新客户端连接时,就把这个这个变量值赋值为最新的,而之前保存的那些字应该给覆盖了。所以最后只有一个fd有效了,因为你把以指针参数的方式传给线程使用。楼主可以动态分配ptr_arg值,每次新客户端连接进来就动态分配一个,再传个线程,这样就应该可以了。


不是这个问题,现在问题已经解决了,非常感谢。
赵4老师 2018-07-13
  • 打赏
  • 举报
回复
参考epoll源代码相关片断。
sghcpt 2018-07-13
  • 打赏
  • 举报
回复
楼主:应该是下面的代码由问题吧?
ptr_arg.protocol = 'T';
ptr_arg.fd = tcp_connectfd;
memcpy((char *)&ptr_arg.sock, (const char *)&client_addr,sizeof(struct sockaddr_in));
ptr_arg.num = i;
if(pthread_create(&pthid, NULL, deal_send_pth, (void *)&ptr_arg) < 0)

其中ptr_arg变量,每次接受到一个新客户端连接时,就把这个这个变量值赋值为最新的,而之前保存的那些字应该给覆盖了。所以最后只有一个fd有效了,因为你把以指针参数的方式传给线程使用。楼主可以动态分配ptr_arg值,每次新客户端连接进来就动态分配一个,再传个线程,这样就应该可以了。
本书通过55个精彩的实例,全面剖析了在Linux下编写网络应用程序的方法,并阐述了网络协议架构和开发规范。为了适应不同读者的需要,本书从最基本的Linux系统操作到网络技术的基本理念,逐步深入至Linux/UNIX下具体的编程实践,结合大量具体实例和编程经验,为读者展现Linux平台下网络编程的魅力。 全书由13章组成,内容涉及到Lindx系统编程基础、TCPUDP协议、套接字编程概念及I/O模型、高级编程中需要用到的进程问通信同步、多路复用、多线程编程和一些高级套接字控制方法、IPv6介绍以及网络安全等。本书最后还汇集了很多网络编程的具体实例,读者可以模仿书中的范例来开发自己的应用程序。 本书内容丰富结构清晰,实例典型,文字简洁流畅,边讲边练。不但是Linux应用与开发的从业人员的指导书,而且也可作为大专院校相关专业师生教学与自学的参考书以及社会初、中级培训班教材。 基础篇 第1章 linux平台环境简单回顾 1.1 文件系统及其操作 1.1.1 文件系统结构 1.1.2 文件i/o操作 1.1.3 文件、目录及操作 1.2 标推输入输出 1.2.1 流和buffer 1.2.2 i/o类型 1.3 进程概念及控制 1.3.1 进程的运行和终止 1.3.2 进程间竞争 1.3.3 wait操作 1.4 信号 1.4.1 信号屏蔽字 1.4.2 相关操作 1.5 本章小结 第2章 进程间通信 2.1 管道和fif0 2.1.1 管道的创建和使用 .2.1.2 实例 2.1.3 popen和pclose函数 2.1.4 fifo的创建和使用 2.1.5 用fif0实现多客户服务 2.1.6 系统对管道和fif0的限制 2.2 消息队列 2.2.1 消息队列的数据结构 2.2.2 消息队列的创建 2.2.3 消息队列的操作 2.2.4 实例 2.2.5 消息队列的限制 2.3 信号量 2.3.1 信号量的数据结构 2.3.2 信号量的创建和操作 2.4 共享内存区 2.4.1 共享内存区的数据结构 2.4.2 共享内存区的创建和操作 2.4.3 实例 2.4.4 共享内存区的限制 2.5 本章小结 第3章 传输层协议tcpudp 3.1 tcp/ip基本框架 3.1.1 网络协议与层次 3.1.2 数据的封装与分用 3.1.3 客户-服务器模型 3.2 用户数据报协议(udp) 3.2.1 udp首部 3.3 传输控制协议(tcp) 3.3.1 顺序传输 3.3.2 保证数据的可靠性与完整性 3.3.3 双向传输 3.3.4 tcp首部 3.4 tcp连接的建立、握手与结束 3.4.1 连接的建立--三方握手 3.4.2 tcp参数 3.4.3 tcp连接的终止 3.5 端口 3.5.1 端口号的分配 3.5.2 套接字对 3.6 缓冲区 3.7 标准internet服务 3.8 本章小结 第4章 tcp套接字简介 4.1 套接字概述 4.2 套接字地址结构 4.3 位顺序调整 4.3.1 字节处理函数 4.3.2 地址转换函数 4.4 建立套接字 4.5 连接 4.5.1 客户端 4.5.2 服务器端 4.6 服务进程创建 4.6.1 函数介绍 4.6.2 范例 4.7 终止连接 4.8 连接地址信息获取 4.9 socket编程client/server应用简单示例 4.9.1 一个简单www浏览器 4.9.2 inetd编程 4.9.3 获取本地ip 4.9.4 dns的使用 4.9.5 从socket中读出一行语句 4.9.6 处理用户登录及权限设置 4.10 本章小结 第5章 tcp套接字编程实例 5.1 tcp客户--服务器实例一 5.1.1 服务器端代码-vcserver.c 5.1.2 客户端代码-vcclient.c 5.1.3 运行结果 5.2 实例之二 5.2.1 服务器端代码-tcpserver.c 5.2.2 客户端代码-tcpclient.c 5.3 本章小结 第6章 udp数据报 6.1 udp通讯机制 6.1.1 基本通讯过程 6.1.2 udptcp的比较 6.1.3 连接udp 6.1.4 udp应用实例 6.2 udp的应用场合 6.3 增加udp的可靠性 6.4 udp编程综合实例 6.5 本章小结 第7章 套接字中的i/o模型 7.1 阻塞式i/o 7.1.1 读阻塞 7.1.2 写阻塞 7.1.3 会接宁建立中的阻塞 7.1.4 实例一 7.1.5 实例二 7.2 非阻塞式i/o 7.2.1 读操作 7.2.2 写操作 7.2.3 建立连接过程 7.2.4 接收连接过程 7.2.5 非阻塞方式的实现 7.3 实例 7.3.1 taik实例 7.3.2 可处理并发服务的echo实例 第8章 套接字属性控制 8.1 获取和设置套接字属性 8.1.1 getsockopt函数和 setsockopt函数 8.1.2 通用套接字属性 8.2 ipv4和ipv6套接字属性 8.3 套接字属性控制 8.3.1 ioctl函数 8.3.2 fcntl函数 8.4 本章小结 提 高 篇 第9章 进程间通讯的同步 9.1 互斥锁 9.1.1 互斥锁的基本原理 9.1.2 互斥锁的基本操作函数 9.1.3 编程实例 9.2 条件变量 9.2.1 条件变量的基本过程 9.2.2 条件变量的操作函数 9.2.3 编程实例 9.3 读写锁 9.3.1 基本原理 9.3.2 读写锁的操作函数 9.4 记录上锁 9.4.1 记录上锁的基本原理 9.4.2 fcntl记录上锁 9.4.3 记录上锁应用举例 9.5 本章小结 第10章 多路复用和信号驱动i/0 10.1 多路复用 10.1.1 多路复用的基本原理 10.1.2 select函数 10.1.3 select应用实例 10.2 poll函数 10.3 多路复用编程实例 10.4 信号驱动i/0 10.5 本章小结 第11章 高级套接字i/0操作 11.1 send和recv函数 11.1.1 send函数 11.1.2 recv函数 11.2 readv和writev函数 11.2.1 readv函数 11.2.2 writev函数 11.3 sendto和recvfrom函数 11.3.1 sendto函数 11.3.2 recvfrom()函数 11.3.3 一个运用sendto()和recvfrom()函数的实例 11.4 recvmsg和sendmsg函数 11.5 辅助数据 11.6 本章小结 第12章 多线程编程及网络应用 12.1 基本概念 12.1.1 引入多线程的原因 12.1.2 线程的基本概念 12.1.3 线程的分类 12.2 线程基础 12.2.1 线程的基本操作函数 12.2.2 简单的多线程编程 12.2.3 修改线程的属性 12.3 线程应用中的同步问题 12.3.1 特定线程数据 12.3.2 互斥锁 12.3.3 条件变量 12.3.4 信号量 12.4 多线程编程的网络应用 12.4.1 函数的多线程安全性 12.4.2 多线程的实际应用 12.5 本章小结 第13章 ip协议及其属性 13.1 ipv4内容 13.1.1 ipv4数据报的格式 13.1.2 ipv4地址 13.1.3 ipv4选项 13.1.4 internet控制报文协议icmp 13.1.5 internet路由选择协议 13.1.6 ipv4的局限性及其缺点 13.2 ipv6内容 13.2.1 ipv6基本头部的格式 13.2.2 ipv4到ipv6的变化 13.2.3 ipv6地址 13.2.4 ipv6的扩展头部 13.2.5 ipv6路由选择 第14章 网络编程的安全性问题 14.1 系统子程序 14.1.1 i/0子程序 14.1.2 进程控制 14.1.3 文件属性 14.1.4 uid和gid的处理 14.2 标准c库 14.2.1 标准i/o 14.2.2 /etc/passwd处理 14.2.3 /etc/group的处理 14.2.4 加密子程序 14.2.5 运行shell 14.3 写安全的c程序 14.4 root程序的设计 14.5 本章小结 实例篇 实例一 ping 实例二 聊天室的实现 实例三 端口扫描程序 实例四 网页更新检查程序 实例五 sniffer的基本实现 实例六 ip包检查程序 实例七 ip欺骗实例 实例八 路由测试程序 实例九 linux防火墙的编写 实例十 守护进程 实例十一 普通文件传输协议(tftp) 附录 附录一 gcc命令选项 1.使用语法 2.选项 附录二 makefile文件的编写方法 1.makefile文件的基本结构 2.makefile文件编写规则 3.makefile变量 4.假象目的 5.函数 6.实用makefile举例 7.一个的功能齐全的makefile 附录三 gdb调试器 1.gdb的基本使用方法 2.gdb命令 3.在gdb下运行程序

69,336

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧