关闭客户端套接字导致nodejs服务器崩溃

5

在C客户端上,我执行以下操作:

socket()
connect() on port 6969
send()
//I have seen that I didn't call recv so nodejs try me to send data but My program was gone
and finally closesocket()

在nodejs服务器上,我收到了消息,因此连接已经建立:
const port = 6969;
var net = require('net');
var server = net.createServer(function(connection) {
    console.log('client connected');
    connection.on('close', function() {
        console.log('conn closed');
    });
    connection.on('end', function() {
        console.log('conn ended');// that is not called
    });
    connection.on("error", function(err) {
        console.log("Caught flash policy server socket error: ");
        console.log(err.stack);
    });
    connection.on('data', function(data) {
        data = data.toString();
        console.log('client sended the folowing string:' + data);
        connection.write("Response");
        console.log('Sended response to client');
    });
});
server.listen(port, function() {
    console.log('server is listening');
});

这是我的终端的结果:

server is listening
client connected
client sended the folowing string:err404
Sended response to client
Caught flash policy server socket error:
Error: read ECONNRESET
    at exports._errnoException (util.js:1018:11)
    at TCP.onread (net.js:568:26)
conn closed

我已经阅读了Node js ECONNRESET,但我不明白为什么我的Node.js服务器会因此崩溃是否属于正常情况?

编辑:我找到了这段代码:

connection.on("error", function(err) {
    console.log("Caught flash policy server socket error: ");
    console.log(err.stack);
});

客户端的这段代码会产生同样的错误:
#ifdef WIN32
Sleep(5000);
int iResult = shutdown(sock, SD_BOTH);
printf("shutdown is called\n");
Sleep(5000);
#elif defined (linux)
sleep(5);
int iResult = shutdown(sock, SHUT_RDWR);
printf("shutdown is called\n");
sleep(5);
#endif // WIN32
    if (iResult == SOCKET_ERROR) {closesocket(sock);printf("SOCKET_ERROR");}
    printf("iResult=%d",iResult);

编辑: 现在我捕获了关闭事件和结束事件:但是仍然抛出相同的错误。

编辑:我已更新代码。 我发现问题所在:NodeJs正试图向我发送数据,但我已经调用了shutdown()

1个回答

4

需要考虑两个方面,一个是服务器端,一个是客户端代码。

服务器端代码:

您需要使用end事件而不是close事件,请参见https://nodejs.org/api/net.html#net_event_end

connection.on('end', function (){
   console.log('client disconnected');
});

结束事件:

当套接字的另一端发送FIN数据包以结束套接字的可读端时,触发此事件。

关闭事件:

套接字完全关闭后触发。参数had_error是一个布尔值,用于表示套接字是否由于传输错误而关闭。

这意味着,在结束事件之后将会发生关闭事件。


客户端代码:

在关闭套接字之前,必须调用shutdown来防止进一步的读写操作,否则会因为套接字已经关闭而导致错误。

shutdown的Windows版本在MSDN上有描述,Linux版本在manpage中有描述。

Windows:

int ret = shutdown(sockfd, SD_BOTH); /* Shutdown both send and receive operations. */

Linux:

int ret = shutdown(sockfd, SHUT_RDWR); /* Disables further send and receive operations. */

刷新已发送数据的重要性:

shutdown 函数不能保证已经在缓冲区中的数据不会发送。在调用 close 之前,需要刷新所有数据。在这个SO答案中提供了一种比仅仅睡眠20毫秒更好的方法。
为了测试是否存在该问题,您可以在 Windows 中使用 Sleep(2000),在 Linux 中使用 sleep(2)shutdownclose 之间睡眠2秒钟。


这个页面上对 close/closesocketshutdown 进行了很好的比较:

You're ready to close the connection on your socket descriptor. This is easy. You can just use the regular Unix file descriptor close() function:

close(sockfd); 

This will prevent any more reads and writes to the socket. Anyone attempting to read or write the socket on the remote end will receive an error.

Just in case you want a little more control over how the socket closes, you can use the shutdown() function. It allows you to cut off communication in a certain direction, or both ways (just like close() does.) Synopsis:

int shutdown(int sockfd, int how);

[...]

shutdown() returns 0 on success, and -1 on error (with errno set accordingly.)


我使用可移植的套接字 #if defined (linux)#define closesocket(s) close(s)#endif,所以在 Linux 上我必须调用 shutdown(socket,SHUT_RDWR); - Et7f3XIV
@elie:在关闭和关闭之间插入2秒的休眠时间,并告诉我它是否有效。您必须确保在关闭之前刷新所有数据。关闭只是防止新数据进入。 - Andre Kampling
1
@elie:你的意思是 if (iResult != SOCKET_ERROR) closesocket(sock); 而不是 if (iResult == SOCKET_ERROR) closesocket(sock);,对吗? - Andre Kampling
好的,我刚刚测试了一下:我在send和closesocket之间放了一个sleep=>我发现shutdown会引起与closesocket相同的错误。我有printf(“%d”,iResult);,它输出0……所以shutdown成功了,但对于NodeJs来说出了些问题。我没有改变==为!=因为这个错误是在之前产生的。 - Et7f3XIV
在关闭套接字之前,我调用了recv:没有抛出错误。是否存在更好的解决方案? - Et7f3XIV
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接