socket perror 为operation on non-socket 解决

出现问题,打log


如 调用connect  socket accept  函数出错,可以 perror("socket"); perror("connect"); printf("%s\n",strerror(errno));都能打出具体的错误


select 函数再次强调:<0 : 出错返回,=0:  正常,超时返回,就是没有fd可读可写,只针对于非阻塞 >0: 正常返回,而且可以调用FDISSET函数去查fd; 






Socket operation on non-socket 错误出现有两种情况:


      1.  建立socket:


                 if(listenfd= socket(AF_INET,SOCK_STREAM, 0)==-1){


                      perror("creating socket failed!");
                      exit(-1);
                 }


           会造成在bind时出现 Socket operation on non-socket错误


           正确的代码应该是:


                  if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
                        perror("creating socket failed!");
                        exit(-1);
                  }


      2.  accept时:


                 if(connfd=accept(listenfd,(struct sockaddr *)&client_addr,(socklen_t *)&sin_size)==-1){
                      perror("accept error!");
                      exit(-1);
                 }


           会造成在recv时出现  Socket operation on non-socket错误


           正确代码是:


                 if((connfd=accept(listenfd,(struct sockaddr *)&client_addr,(socklen_t *)&sin_size))==-1){
                         perror("accept error!");
                         exit(-1);
                 }


   出现Socket operation on non-socket 错误的原因是:


            if(listenfd= socket(AF_INET,SOCK_STREAM, 0)==-1)


            if(connfd=accept(listenfd,(struct sockaddr *)&client_addr,(socklen_t *)&sin_size)==-1)


   这两句中缺失了()造成的。赋值符合优先级最低,导致listenfd和connfd在创建/连接成功是为0,不成功时为1
<think>我们正在解决一个套接字编程中的错误:“Writeendclosed:Socketoperationonnon-socketerror”根据引用[1]:关闭套接字后,所有后续操作都会失败。远程端将不会再收到数据(在队列数据被刷新后)。套接字在垃圾回收时会自动关闭。引用[2]展示了客户端创建套接字并连接的代码示例。引用[3]解释了listen函数将主动套接字转换为被动套接字(监听状态)。引用[4]则提供了处理SIGPIPE信号(管道破裂)和EPIPE错误的方法。用户遇到的错误信息包含两部分:1."Writeendclosed":表示写端已经关闭,这通常发生在尝试写入一个已经被关闭的套接字(或管道)时。2."Socketoperationonnon-socket":表示操作的对象不是一个有效的套接字描述符。结合引用,我们可以推断:-程序可能试图在一个已经关闭的套接字上执行写入操作(导致“Writeendclosed”)。-或者,在写入之前,套接字描述符已经被关闭,甚至可能已经被释放(导致描述符无效,从而出现“non-socket”错误)。以下分析原因和解决方案:###错误原因分析1.**套接字被提前关闭**:-在写入之前,套接字已经被调用`close()`关闭,但程序仍尝试写入。-可能由于多线程环境下,一个线程关闭了套接字,而另一个线程仍在尝试写入。2.**套接字描述符无效**:-套接字描述符被关闭后,其文件描述符可能被重用(例如用于打开其他文件或套接字),此时再对该描述符进行套接字操作就会出错。-或者,程序错误地使用了未初始化的描述符(例如未正确创建套接字)。3.**未处理SIGPIPE信号**:-默认情况下,向一个已关闭写端的套接字写入数据会触发SIGPIPE信号,该信号默认行为是终止进程。如果程序捕获了该信号但未正确处理,可能继续尝试写入,导致后续错误。-引用[4]提到,可以捕获SIGPIPE信号或者检查EPIPE错误。4.**套接字创建失败**:-在创建套接字时,如果失败(例如资源不足),则后续的connect、write等操作都会因为描述符无效而失败。###解决方案####1.确保套接字有效-在每次使用套接字描述符前,检查其有效性。但注意:在关闭后,描述符会变为无效,因此更重要的是在逻辑上保证关闭后不再使用。-检查套接字创建是否成功:```cintsockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("socketcreationfailed");exit(EXIT_FAILURE);}```####2.处理SIGPIPE信号(避免进程终止)-根据引用[4],我们可以设置忽略SIGPIPE信号,或者捕获它:```c#include<signal.h>signal(SIGPIPE,SIG_IGN);//忽略SIGPIPE信号```或者使用更健壮的sigaction(如引用[4]中的示例)来捕获信号。-另一种方法是检查每次写入的返回值,如果返回`EPIPE`错误(即errno被设为EPIPE),则表示对端已经关闭,此时应停止写入:```cssize_tn=write(sockfd,buf,len);if(n==-1){if(errno==EPIPE){//对端已经关闭,关闭本端套接字并清理资源close(sockfd);sockfd=-1;//将描述符置为无效,避免再次使用}else{//其他错误处理}}```####3.管理套接字生命周期(避免使用已关闭的套接字)-在关闭套接字后,立即将描述符变量设置为无效值(如-1),并在使用前检查。-在多线程环境中,使用互斥锁保护套接字,确保关闭和写入操作不会同时发生。####4.检查连接状态-在写入前,可以通过`getpeername`或`getsockopt`等函数检查套接字是否仍然连接,但更常见的做法是直接写入并处理错误(因为即使检查时连接存在,写入时也可能断开)。-对于TCP套接字,如果对端已经关闭连接,那么本端写入会触发SIGPIPE或返回EPIPE错误。####5.示例代码修正-参考引用[2]中的客户端代码,在连接失败时退出,但写入时没有错误处理。我们应添加写入错误处理:```c//假设已经成功连接char*message="Hello,server";ssize_tbytes_sent=send(clientSock,message,strlen(message),0);if(bytes_sent<0){if(errno==EPIPE){fprintf(stderr,"Connectionclosedbypeer\n");}else{DieWithError("send()failed");}close(clientSock);clientSock=-1;}```###总结出现“Writeendclosed:Socketoperationonnon-socket”错误,通常是因为:-套接字已经被关闭,但程序仍尝试写入(导致写端关闭错误)。-套接字描述符无效(可能被关闭后重用,或从未成功创建)。解决方法:1.确保套接字创建成功。2.在套接字关闭后不再使用,并设置描述符为无效值(如-1)。3.处理SIGPIPE信号或检查EPIPE错误。4.在多线程环境中使用锁保护套接字操作。通过以上步骤,可以避免此类错误。§§相关问题§§1.如何在多线程程序中安全地关闭套接字?2.忽略SIGPIPE信号和捕获SIGPIPE信号哪种方式更好?3.除了EPIPE,还有哪些错误表示套接字连接已断开?</think>### 套接字编程中的 "Write end closed: Socket operation on non-socket" 错误分析与解决 这个错误表明程序尝试在**已关闭的套接字**或**无效的文件描述符**上进行写入操作。结合引用内容,以下是核心原因和解决方案: --- #### 一、错误原因分析 1. **套接字已关闭但仍在操作** [^1] - 当套接字被`close()`后,所有后续操作都会失败 - 常见于多线程环境中:一个线程关闭套接字,另一个线程仍在尝试写入 2. **无效文件描述符** [^4] - 尝试操作未初始化的套接字描述符 - 套接字创建失败(如`socket()`返回负值)但未检查错误 - 文件描述符被意外重用(如关闭后未置为-1) 3. **未处理管道破裂(SIGPIPE)** [^4] - 向已关闭的套接字写入会触发`SIGPIPE`信号 - 默认行为是终止进程,导致"non-socket"错误 4. **连接状态管理不当** [^3] - 混淆主动套接字(connect)和被动套接字(listen) - 尝试在监听套接字上执行写入操作 --- #### 二、解决方案指南 ##### 1. 检查套接字状态(基础防御) ```c // 创建套接字后必须检查有效性 int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 执行操作前验证描述符 if (fcntl(sockfd, F_GETFD) == -1 && errno == EBADF) { perror("Invalid socket descriptor"); return; } ``` ##### 2. 正确处理SIGPIPE信号(关键)[^4] ```c #include <signal.h> // 方法1:忽略SIGPIPE信号 signal(SIGPIPE, SIG_IGN); // 方法2:捕获并处理SIGPIPE void sigpipe_handler(int signum) { printf("Caught SIGPIPE, closing socket\n"); // 清理资源 } int main() { struct sigaction sa; sa.sa_handler = sigpipe_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGPIPE, &sa, NULL); // ...套接字操作代码... } ``` ##### 3. 安全写入模式(带错误检测) ```c ssize_t write_data(int fd, const void* buf, size_t len) { ssize_t bytes_sent = send(fd, buf, len, MSG_NOSIGNAL); // 避免触发SIGPIPE if (bytes_sent == -1) { if (errno == EPIPE) { // 对端已关闭 printf("Write end closed\n"); close(fd); return -1; } else if (errno == EBADF) { // 无效描述符 perror("Operation on non-socket"); return -1; } } return bytes_sent; } ``` ##### 4. 连接生命周期管理 - **主动套接字** (客户端)[^2]: ```c connect(sockfd, ...); // 成功后才能读写 ``` - **被动套接字** (服务端)[^3]: ```c listen(sockfd, 5); // 只能接受连接,不能直接读写 int client_fd = accept(sockfd, ...); // 返回的新套接字用于通信 ``` ##### 5. 多线程安全实践 ```c // 全局套接字描述符 volatile int active_socket = -1; // 关闭套接字的线程安全函数 void safe_close(int* sock) { pthread_mutex_lock(&sock_mutex); if (*sock != -1) { shutdown(*sock, SHUT_RDWR); close(*sock); *sock = -1; // 标记为无效 } pthread_mutex_unlock(&sock_mutex); } ``` --- #### 三、预防措施 1. **描述符生命周期规则**: - 关闭后立即置为-1 - 使用前检查`fcntl(fd, F_GETFL) != -1` 2. **错误处理三原则**: ```c if (operation() == -1) { // 1.检查返回值 perror("reason"); // 2.打印错误 handle_error(); // 3.清理资源 } ``` 3. **协议设计建议**: - 添加心跳机制检测连接状态 - 使用应用层ACK确认机制 > **调试提示**:使用`strace -e trace=network`追踪套接字系统调用,观察`close()`和`write()`的执行顺序[^1][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值