send函数引发线程退出

在linux下进行send函数通信时,客户端断开socket,偶尔会导致服务端线程退出,通过网上查找资料,并参考了http://blog.youkuaiyun.com/think_nothing/article/details/17006179

得出退出原因,总结如下:


在linux下send函数原型为:

#include <sys/types.h>

 #include <sys/socket.h>

 ssize_t send(int sockfd, const void *buf, size_t len, int flags);

其中“flags”被忽略了,一般设置为0,但当flags为0时,如果客户端断开,继续往里边写数据的话,会引发一个信号SIGPIPE,此信号会引发线程的退出。


所以,将“flags”设置为MSG_NOSIGNAL,则不会导致线程退出。

MSG_NOSIGNAL的含义,通过man send,说明如下:

 MSG_NOSIGNAL (since Linux 2.2)
              Requests not to send SIGPIPE on errors on stream oriented sockets when  the
              other end breaks the connection.  The EPIPE error is still returned.

意思是,当对方断开连接导致错误时,不发送SIGPIPE信号。但还是会返回EPIPE错误。

于是,只需要判断send是否成功就可以了。



<think>在将多线程服务器改为多进程服务器,`send_response`函数可以保持不变,因为该函数不涉及线程共享数据,它只依赖于传入的文件描述符和文件路径,这些在每个进程中是独立的。因此,在多进程模型中,该函数可以原样使用。 ### 原因分析: 1. **无共享状态**:该函数不访问全局变量或共享资源,所有数据都是通过参数传递的局部变量。 2. **文件描述符独立**:每个进程拥有自己独立的文件描述符副本,互不干扰。 3. **文件操作安全**:对本地文件的读取操作是线程安全和进程安全的(因为每个进程操作不同的文件描述符)。 ### 注意事项: 虽然函数逻辑不变,但需注意以下两点: 1. **文件路径安全性**:确保路径拼接正确(特别是处理客户端请求路径需防范路径遍历攻击) 2. **资源释放**:在多进程中需确保所有打开的文件描述符都被正确关闭(包括失败情况) ### 示例代码片段(保持原样): ```c /* 发送HTTP响应 */ void send_response(int client_fd, const char *path) { // ... 原有代码完全不变 ... } ``` ### 多进程模型下的完整调用示例: ```c void handle_client(int client_fd) { // ... 解析请求获取路径 ... send_response(client_fd, final_path); // 调用方式不变 } ``` ### 安全增强建议: 在正式环境中,建议添加路径安全检查: ```c // 在调用send_response前检查路径是否合法 if (strstr(path, "..")) { // 简单检查上级目录遍历 send_403_forbidden(client_fd); return; } ``` ### 结论: `send_response`函数可以不做修改直接用于多进程模型,因为其功能与并发模型无关。 §§相关问题§§ 1. 在多进程模型中,为什么可以共享相同的`send_response`函数? 2. 如何防止客户端通过路径遍历(如`../../etc/passwd`)访问敏感文件? 3. 在多进程环境下,打开的文件描述符需要特别注意什么? 4. 如果响应大文件(如100MB),这个函数会有什么性能问题? 5. 如何修改`send_response`函数支持HTTP范围请求(Range Requests)?</think>在多进程模型中,`send_response`函数可以**完全保持与线程版本相同**,无需修改。以下是详细分析和原因说明: ### 保持不变的可行性分析 1. **无共享状态**: - 函数内部使用局部变量(`header`, `buffer`, `st`) - 不依赖任何全局变量或共享资源 - 每个进程有自己的独立内存空间 2. **文件操作安全**: - `open/read/close`操作是线程安全的 - 文件描述符是进程独立的 - 文件指针不会在进程间冲突 3. **网络操作安全**: - `send`操作使用独立的客户端套接字 - 套接字描述符在进程间不共享 ### 推荐保持原样的关键代码 ```c /* 发送HTTP响应 */ void send_response(int client_fd, const char *path) { char header[BUFFER_SIZE]; // 响应头 char buffer[BUFFER_SIZE]; // 内容缓冲区 struct stat st; // 文件状态 // 文件不存在处理(保持相同) if (stat(path, &st) == -1) { snprintf(header, BUFFER_SIZE, "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<h1>404 Not Found</h1>"); send(client_fd, header, strlen(header), 0); return; } // 文件读取和发送(保持相同) int fd = open(path, O_RDONLY); if (fd < 0) return; snprintf(header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n\r\n", get_content_type(path), st.st_size); send(client_fd, header, strlen(header), 0); while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) { send(client_fd, buffer, bytes_read, 0); } close(fd); } ``` ### 需要特别注意的方面 1. **文件描述符管理**: - 确保在子进程中关闭不需要的文件描述符 - 父进程关闭客户端套接字(避免泄漏) 2. **错误处理增强**: ```c // 添加更详细的错误日志 if (fd < 0) { perror("open failed"); // 发送500错误响应 const char *err = "HTTP/1.1 500 Internal Server Error\r\n\r\n"; send(client_fd, err, strlen(err), 0); return; } ``` 3. **性能优化建议**: - 使用`sendfile()`系统调用提高大文件传输效率 - 添加缓存机制减少磁盘IO ### 多进程模型下的调用示例 ```c void handle_client(int client_fd) { // ...解析请求路径... send_response(client_fd, path); // 直接调用不变 close(client_fd); // 关闭客户端套接字 exit(0); // 子进程退出 } ``` ### 结论 `send_response`函数在进程模型中可以**完全重用**,因为: 1. 不依赖任何线程特定机制 2. 所有资源都是进程隔离的 3. 函数本身是无状态的纯功能实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值