3

我有一个循环,它通过 TCP/IP 不断向客户端写入数据。连接打开如下:

newsockfd = accept(sockfd,
            (struct sockaddr *) &cli_addr,
            &clilen);

以下行在循环中连续执行(睡眠时间为 0.1 秒),以便将数据写入客户端:

n = write(newsockfd,data.c_str(),data.length()+1); //+1 to include NULL in null terminated string
if(n>=0)
{
    cout<<"success"<<endl;
}
else
{
    cout<<"Fail"<<endl;
    close(newsockfd);
    newsockfd = -1;
}

如果连接因任何原因断开,我希望服务器能够读取以接收新连接。因此,如果写入失败,我将再次准备好接受与第一个命令的新连接。

我的问题如下:该方法第一次成功,所以如果从客户端断开连接,write() 返回一个负数,我立即知道连接有问题,所以我关闭它并期待一个新的一。服务器收到新的连接,但下次使用 write() 时,程序立即崩溃。

为什么会这样?请帮忙,我是 TCP/IP 方面的新手。

如果您需要,请询问更多信息。

求助者要求:

堆栈跟踪:

错误:信号 13:

    /mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402155]
    /lib/x86_64-linux-gnu/libc.so.6(+0x364a0)[0x7ffc57ac04a0]
    /lib/x86_64-linux-gnu/libpthread.so.0(write+0x10)[0x7ffc5836dcb0]
    /mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x4023b6]
    /mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x401b54]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffc57aab76d]
    /mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402081]

变量定义:它是一个类:

身体:

int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;

构造函数启动的东西:

LinuxTCPServer::LinuxTCPServer(int port, bool nonblocking)
{
if(nonblocking)
    sockfd = socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0);
else
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0)
   error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = port;

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);

if (bind(sockfd, (struct sockaddr *) &serv_addr,
         sizeof(serv_addr)) < 0)
         error("ERROR on binding");

listen(sockfd,5);
clilen = sizeof(cli_addr);
}
4

2 回答 2

5

假设 Linux >= 2.2,替换这个:

n = write(newsockfd,data.c_str(),data.length()+1);

有了这个:

n = send(newsockfd, data.c_str(), data.length()+1, MSG_NOSIGNAL);

send(2)然后将返回 -1 并将 errno 设置为 EPIPE,而不是生成致命的 SIGPIPE。或者,忽略 SIGPIPE。

当您收到 SIGPIPE 时,后面的连接newsockfd已断开。我们没有足够的代码来重现问题、客户端和服务器,所以说实际上可能出了什么问题是没有实际意义的。但是,将 SIGPIPE 转换为 EPIPE 至少会让您的服务器有机会处理断开的连接。

于 2013-04-03T19:14:15.543 回答
2

您的堆栈跟踪表明程序因信号 13 而崩溃,这意味着您的管道已损坏。

这表明您的连接已断开,但您仍在尝试写入。请参阅此线程以了解为什么这可能导致管道损坏错误:是什么导致了管道损坏错误?

现在,关于如何解决这个问题,我怀疑您实际上并没有在您的“接受”呼叫中获得正确的连接设置。确保在调用 write 之前检查“接受”调用的状态。

我认为导致您的接受呼叫失败的问题可能在连接的另一端。

于 2013-04-03T18:11:55.310 回答