socket编程遇到SIGPIPE(broken pipe)错误信号

人哎的微博 2014-01-02 10:39:56
Environment: CentOS 5.6 x86 / GCC

我练习socket编程,写了一个server和一个client,UNIX套接字的,server不断接收消息并打印出来,client是一个交互程序,输入一个消息回车发送,接着又可以输入消息。

出问题了:
当server监听着,client第一次发送消息成功,server接收并打印出来了。
client第二次发送消息没成功并且结束程序了,server没接收到消息,保持继续监听。

我用GDB调试时,发现client第二次发送消息时,client收到SIGPIPE(Broken Pipe)信号。网上搜索,说是对方端关闭,所以发送失败,但我明明看到server还监听着,而且再次启动client还是第一次成功,第二次失败退出。大家看一下我的代码:


// socket-server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

// 服务端:不断从套接字读取并输出文本信息直到套接字关闭。当客户端发送"quit"消息>时返回非 0 值,否则返回 0
int server(int client_socket)
{
while(1) {
int length; /* 消息的长度 */
char* text_buf; /* 保存信息的缓冲区 */

// 获取消息长度。如果 read 返回 0 说明客户端关闭了连接
if(read(client_socket, &length, sizeof(length)) == 0)
return 0;

// 分配用于保存信息的缓冲区
text_buf = (char*) malloc(length);
// 读取并输出信息
read(client_socket, text_buf, length);

// 如果客户发送"quit"消息,结束任务
if(!strcmp(text_buf, "quit"))
{
// 释放缓冲区
free(text_buf);
return 1;
}

printf("Client says: %s\n", text_buf);
// 释放缓冲区
free(text_buf);

return 0;
}
}

int main()
{
const char* socket_name = "/tmp/socket"; /* 套接字路径名 (/path/filename) */
int socket_fd; /* 套接字文件描述符 */
struct sockaddr_un name; /* 监听套接字地址结构 */
int client_sent_quit_message; /* 布尔值:客户端是否发送了"quit"消息 */

// 创建套接字: 本地套接字,连接型
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
// 将服务器地址写入套接字地址结构
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, socket_name);
// 绑定套接字,指明这是服务器
bind(socket_fd, (struct sockaddr*) &name, SUN_LEN(&name));
// 监听连接,最大允许尝试连接数为 5
listen(socket_fd, 5);

// 不断接受连接,循环调用 server() 处理连接。直到客户发送"quit"消息时推出
do {
struct sockaddr_un client_name; /* 工作套接字地址结构 */
socklen_t client_name_len; /* 套接字地址结构的大小 */
int client_socket_fd; /* 处理客户端连接的套接字文件描述符 */

// 接受连接
client_socket_fd = accept(socket_fd, (struct sockaddr*) &client_name, &client_name_len);
// 调用 server() 处理连接
client_sent_quit_message = server(client_socket_fd);
// 关闭服务器端连接到客户端的套接字
close(client_socket_fd);
} while(!client_sent_quit_message);

// 删除套接字文件
close(socket_fd);
unlink(socket_name);

return 0;
}



// socket-client-interactive.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

// 将 text 的内容通过 socket_fd 代表的套接字发送
void send_text(int socket_fd, char* text)
{
// 输出字符串的长度(包含结尾的NUL字符)
int length = strlen(text) + 1;
write(socket_fd, &length, sizeof(length));
// 输出字符串
write(socket_fd, text, length);
}

int main()
{
const char* socket_name = "/tmp/socket";
char* message;
int socket_fd;
struct sockaddr_un name;

// 创建套接字
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
// 将服务器地址写入套接字地址结构
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, socket_name);
// 连接套接字
connect(socket_fd, (struct sockaddr*) &name, SUN_LEN(&name));

while(1) {
printf(">");
scanf("%s", message);
fflush(stdin);
if (message == NULL) {
continue;
}
// 调用 send_text() 将制定消息写入套接字
send_text(socket_fd, message);
}

// 关闭套接字
close(socket_fd);

return 0;
}


我对交互式输入输出比较薄弱,在client接收输入的部分可能写的不好,大家注意一下。
...全文
1023 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2014-01-05
  • 打赏
  • 举报
回复
SIGPIPE是正常的信号,对端断开后本端协议栈在向对端传送数据时,对端会返回TCP RST,导致本端抛出SIGPIPE信号。 所有的网络程序都应该sigprocmask主动屏蔽掉这个信号。
max_min_ 2014-01-04
  • 打赏
  • 举报
回复

 // 关闭服务器端连接到客户端的套接字
        close(client_socket_fd);

//这个不需要的!链路已经半关闭了,TIME_WAIT
人哎的微博 2014-01-03
  • 打赏
  • 举报
回复
引用 2 楼 missheaven2011 的回复:
// 关闭服务器端连接到客户端的套接字 close(client_socket_fd); 这里你不就把服务端的套接字关闭掉了嘛,第二次肯定不行啦
对的,我把close(client_socket_fd);这行注释掉,客户端就可以多次发送消息,不报SIGPIPE了。 但是服务器端只读取到了第一条消息,如何让它不断读取客户端发送的消息
missheaven2011 2014-01-03
  • 打赏
  • 举报
回复
        
引用 3 楼 haoren026 的回复:
[quote=引用 2 楼 missheaven2011 的回复:] // 关闭服务器端连接到客户端的套接字 close(client_socket_fd); 这里你不就把服务端的套接字关闭掉了嘛,第二次肯定不行啦
对的,我把close(client_socket_fd);这行注释掉,客户端就可以多次发送消息,不报SIGPIPE了。 但是服务器端只读取到了第一条消息,如何让它不断读取客户端发送的消息[/quote] // 接受连接 client_socket_fd = accept(socket_fd, (struct sockaddr*) &client_name, &client_name_len); accept函数导致第二次接收数据被堵塞,你可以将套接字设置为非阻塞,也可以将这个函数的调用提前,放在while循环外面
missheaven2011 2014-01-02
  • 打赏
  • 举报
回复
// 关闭服务器端连接到客户端的套接字 close(client_socket_fd); 这里你不就把服务端的套接字关闭掉了嘛,第二次肯定不行啦
minglianga1988 2014-01-02
  • 打赏
  • 举报
回复
服务端第一次接收数据之后已经将该连接关闭了,但是客户端没有关闭,继续往这条链接发送数据,自然报SIGPIPE(Broken Pipe)了。

70,020

社区成员

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

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