Linux下Socket编程遇到的问题和总结

1.向已关闭的fd写入数据的时候造成的程序退出解决办法

问题描述:
当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。
又或者当一个进程向某个已经收到RST的socket执行写操作是,内核向该进程发送一个SIGPIPE信号。该信号的缺省学位是终止进程,因此进程必须捕获它以免不情愿的被终止。
我遇到的情况是客户端socket句柄已关闭,然后服务器像一个已关闭的客户端连接句柄中执行写操作,从而产生了SIGPIPE信号。
问题原因:
根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以进程会退出。
系统里边定义了三种处理方法: 
    1)SIG_DFL     
    2)SIG_IGN     
    3)SIG_ERR     
根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以进程会退出。若不想客户端退出,需要把 SIGPIPE默认执行动作屏蔽。
问题解决:
将SIGPIPE的默认处理方法屏蔽,我找到了两种方法:用signal(SIGCHLD,SIG_IGN)或者重载其处理方法。个人选了后者。两者区别在于signal设置的信号句柄只能起一次作用,信号被捕获一次后,信号句柄就会被还原成默认值了;sigaction设置的信号句柄,可以一直有效,值到你再次改变它的设置。具体代码如下:
struct sigaction action;
action.sa_handler = handle_pipe;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGPIPE, &action, NULL);
void handle_pipe(int sig)
{//不做任何处理即可}
在源文件中要添加signal.h头文件:#include <signal.h>

参考自:http://blog.sina.com.cn/s/blog_6f7c07a00101g7u3.html

2.read函数读取空数据并不是像accept函数那样执行无限挂起操作

当使用read函数读取套接字的时候,当数据已被取完,而客户端又没有发送数据的时候,read会挂起,但并不是永久的,有一个超时时间,超过以后就会返回0,也就是读取了0个字节,这个时候得特殊处理。

3.多线程接收客户端请求的时候不能用局部变量传递fd

由于Linux下创建线程传递的是参数指针,而不是参数本身,所以参数不是按值复制给函数的,如果直接将局部变量的地址传递给线程函数的话,可能那个值在主循环中的下一次循环里已经改变了,变成了下一个客户的fd,这个时候前一个子线程获取的fd就是改变后的fd,这会造成严重的问题。所以在创建线程之前,需要单独用malloc等函数分配一块内存空间,用于存放当前fd的拷贝,或者干脆一开始就使用分配的内存空间来存储accept返回的fd,将分配的内存空间的地址传递作为线程的参数,而该内存空间由各线程自己负责清理释放。

标签: none

添加新评论