当前位置: 技术问答>linux和unix
socket与多线程/进程编程的问题。
来源: 互联网 发布时间:2016-03-11
本文导语: 想设计一个服务器,对于每一个客户端的连接都分配一个线程或者进程。 今天写了一些测试功能用的小程序(假设有2个客户端),有些问题想请教大家。 1.在主进程中(也就是main函数) 初始化socket一直到listen, 然...
想设计一个服务器,对于每一个客户端的连接都分配一个线程或者进程。
今天写了一些测试功能用的小程序(假设有2个客户端),有些问题想请教大家。
1.在主进程中(也就是main函数) 初始化socket一直到listen, 然后在进程/线程中 accept,
可以正确接收客户端信息,想请问为什么线程中accept后的客户端client_fd是不同的,而进程却是相同的。
sockfd = socket(...);
....
listen( sockfd, .. );
pid = fork();
if( pid == 0) {
client_fd = accept( ... );
....
}else if( pid > 0 ) {
client_fd = accept( ... );
....
}
// client_fd 是相同的。
而如果用线程的话,则得到的是不同的。 为什么?
2. 如果把 sokcet 初始化 一直到listen 分别放入2个进程/线程中,则总会有一个客户端的信息收不到,在accept处被一直阻塞。为什么?
今天写了一些测试功能用的小程序(假设有2个客户端),有些问题想请教大家。
1.在主进程中(也就是main函数) 初始化socket一直到listen, 然后在进程/线程中 accept,
可以正确接收客户端信息,想请问为什么线程中accept后的客户端client_fd是不同的,而进程却是相同的。
sockfd = socket(...);
....
listen( sockfd, .. );
pid = fork();
if( pid == 0) {
client_fd = accept( ... );
....
}else if( pid > 0 ) {
client_fd = accept( ... );
....
}
// client_fd 是相同的。
而如果用线程的话,则得到的是不同的。 为什么?
2. 如果把 sokcet 初始化 一直到listen 分别放入2个进程/线程中,则总会有一个客户端的信息收不到,在accept处被一直阻塞。为什么?
|
fd是per process的概念。当child process fork出来时,它拥有的fd table是其父进程的一个copy,根据unix分配fd的原则,即总是分配一个最小的空余fd号,所以所有子进程里接受new connection,分配的fd都一样,都是他们父进程空闲的那个最小值。
同样的道理,如果利用线程的话,则是在自己所在的process里找最小的那个空闲值,所以每个新的都会增大1。
同样的道理,如果利用线程的话,则是在自己所在的process里找最小的那个空闲值,所以每个新的都会增大1。
|
1. 同楼上
2. 同一个socket,可以对应多个句柄,而实际上的对应的内核中是同一个socket对象
多进程同时监听同一个socket,虽然由于是多个进程空间中,socket句柄是两个,但是内核中的socket对象是一个
所以同时只能有一个进程响应
多线程同时监听一个socket,进程中的socket句柄是同一个,对应的内核中的socket对象也是一个,同时也只能有一个线程响应
2. 同一个socket,可以对应多个句柄,而实际上的对应的内核中是同一个socket对象
多进程同时监听同一个socket,虽然由于是多个进程空间中,socket句柄是两个,但是内核中的socket对象是一个
所以同时只能有一个进程响应
多线程同时监听一个socket,进程中的socket句柄是同一个,对应的内核中的socket对象也是一个,同时也只能有一个线程响应
|
第一个问题:解释一下线路和进程的概念,假设程序是一个房子,SOCKET连接就是椅子,即文件client_fd就是椅子,如果有两个SOCKET连接的话,就有两把椅子,你所说的client_fd的值就是椅子摆放的位置,假设椅子都是从房子中间向两把摆。
那么如果用进程的方式处理的话,就相当于再复制了一个房子,两个房子的摆设是一模一样的,那么自然两个房子中间同样的位置都有这么一把椅子,也就是说当需要摆设椅子的时候,两个房子中的椅子都可以摆到房子的中间,所以其值是一模一样的。
但是如果用线程的话,就相当于只在一个房子中摆椅子,打一把椅子可以摆在房子中间,但是第二把、第三把都必须摆设到其它不同的位置,所以显示出来的值就不一样了!
第二个问题:最简单的解决方法是在
listen( sockfd, .. );
pid = fork();
if( pid == 0) {
client_fd = accept( ... );
....
}else if( pid > 0 ) {
client_fd = accept( ... );
这段代码的外围加上一个while循环来包其来就可以了。实际真正的理解你就需要查看一下SOCKET数据了,建议你找以下Unix下面的C语音编程书籍看一看
那么如果用进程的方式处理的话,就相当于再复制了一个房子,两个房子的摆设是一模一样的,那么自然两个房子中间同样的位置都有这么一把椅子,也就是说当需要摆设椅子的时候,两个房子中的椅子都可以摆到房子的中间,所以其值是一模一样的。
但是如果用线程的话,就相当于只在一个房子中摆椅子,打一把椅子可以摆在房子中间,但是第二把、第三把都必须摆设到其它不同的位置,所以显示出来的值就不一样了!
第二个问题:最简单的解决方法是在
listen( sockfd, .. );
pid = fork();
if( pid == 0) {
client_fd = accept( ... );
....
}else if( pid > 0 ) {
client_fd = accept( ... );
这段代码的外围加上一个while循环来包其来就可以了。实际真正的理解你就需要查看一下SOCKET数据了,建议你找以下Unix下面的C语音编程书籍看一看
|
楼主想设计一个服务器,最好是父进程专门管监视子进程的状态(用wait方法),然后子进程中创建线程,用于接收用户请求,并维护每个客户端的socket,最好用select模型,对了,一定要有延迟处理