客户端中的关闭套接字使Node.js服务器崩溃

Et7*_*XIV 5 c sockets node.js

在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()
Run Code Online (Sandbox Code Playgroud)

在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');
});
Run Code Online (Sandbox Code Playgroud)

这是我的终端的结果:

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
Run Code Online (Sandbox Code Playgroud)

所以我已经阅读了Node js ECONNRESET,但我不明白这是否正常,为什么我的nodejs服务器崩溃?

编辑:我发现此代码段:

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

客户端上的此代码将产生相同的错误:

#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);
Run Code Online (Sandbox Code Playgroud)

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

编辑:我已经更新了我的代码。我发现了问题所在:NodeJs试图向我发送数据,但我已经打电话给了shutdown()

And*_*ing 4

有两件事需要考虑,一件事在你的服务器中,一件事在你的客户端代码中。

服务器代码:

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

connection.on('end', function (){
   console.log('client disconnected');
});
Run Code Online (Sandbox Code Playgroud)

结束事件:

当套接字的另一端发送 FIN 数据包时发出,从而结束套接字的可读端。

关闭事件:

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

这意味着,该close事件将在该事件之后发生end


客户端代码:

您必须shutdown在关闭套接字之前调用,以防止进一步的读取或写入,这会导致错误,因为套接字已经关闭。

Windows 版本在 MSDN 中shutdown进行了描述,Linux 版本在联机帮助页中进行了描述。

视窗:

int ret = shutdown(sockfd, SD_BOTH); /* Shutdown both send and receive operations. */
Run Code Online (Sandbox Code Playgroud)

Linux:

int ret = shutdown(sockfd, SHUT_RDWR); /* Disables further send and receive operations. */
Run Code Online (Sandbox Code Playgroud)

刷新发送数据的重要性:

shutdown函数不保证缓冲区中已有的数据不会被发送。需要在调用close发生之前刷新所有数据。在这个关于 SO 的答案中,写下了一个很好的方法来做到这一点,而不仅仅是睡眠 20 毫秒左右。
为了测试这是否是您的问题,您可以Sleep(2000)在 Windows 和Linux 中使用和sleep(2)之间休眠 2 秒。shutdownclose


此页面上有close/closesocket和之间的很好的比较shutdown

您已准备好关闭套接字描述符上的连接。这很容易。你可以使用常规的 Unix 文件描述符 close() 函数:

close(sockfd); 
Run Code Online (Sandbox Code Playgroud)

这将防止对套接字进行更多的读取和写入。任何尝试在远程端读取或写入套接字的人都会收到错误。

如果您想对套接字关闭方式进行更多控制,可以使用 shutdown() 函数。它允许您切断某个方向或双向的通信(就像 close() 所做的那样。)概要:

int shutdown(int sockfd, int how);
Run Code Online (Sandbox Code Playgroud)

[...]

shutdown() 成功时返回 0,出错时返回 -1(相应设置 errno。)