在网络编程中,接受端必须关闭两个套接字吗?

huangapple go评论62阅读模式
英文:

In network programming, must the accepting end close both sockets?

问题

以下是翻译好的部分:

我之前提出了一个问题,其中一个答案涉及另一个问题。

也就是说,一般情况下,接收端应该创建两个套接字来建立接受端。就像这样:

Python

from socket import *
sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
# ...
client_sockfd.close()
sockfd.close()

C

int sockfd, client_sockfd;
sockfd = socket(...);
// ...
client_sockfd = accept(sockfd, ...);
// ...
shutdown(client_sockfd, 2);
shutdown(sockfd, 2);
close(client_sockfd);
close(sockfd);

所以我们可以跳过创建 client_sockfd 变量的任务吗?像这样:

Python

sockfd = socket(...)
# ...
sockfd, addr = sockfd.accept()
# ...
sockfd.close()

C

int sockfd;
struct sockaddr_in server, client;
socklen_t client_size = sizeof(client);
sockfd = socket(...);
// ...
sockfd = accept(sockfd, (struct sockaddr *)&client, &client_size);

或者可以像这样:

Python

sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
sockfd.close()
# ...
client_sockfd.close()

C

int sockfd = socket(...);
int client_sockfd;
// ...
client_sockfd = accept(sockfd, ...);
shutdown(sockfd, 2);
close(sockfd);
// ...
shutdown(client_sockfd, 2);
close(client_sockfd);

如上所示的代码,我们可以只使用一个套接字来完成整个网络编程的接受端吗?这样做有问题吗?(至少我自己写程序时没有遇到任何问题)

英文:

I raised a question earlier, and one of the answers involved another question.

That is to say, in general, the accepting end should create two sockets to establish the accepting end. like this:

Python

from socket import *
sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
# ...
client_sockfd.close()
sockfd.close()

C

int sockfd, client_sockfd;
sockfd = socket(...);
// ...
client_sockfd = accept(sockfd, ...);
// ...
shutdown(client_sockfd, 2);
shutdown(sockfd, 2);
close(client_sockfd);
close(sockfd);

<hr>

So can we skip the task of creating the client_sockfd variable? like this:

Python

sockfd = socket(...)
# ...
sockfd, addr = sockfd.accept()
# ...
sockfd.close()

C

int sockfd;
struct sockaddr_in server, client;
socklen_t client_size = sizeof(client);
sockfd = socket(...);
// ...
sockfd = accept(sockfd, (struct sockaddr *)&amp;client, &amp;client_size);

Or it could be like this:

Python

sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
sockfd.close()
# ...
client_sockfd.close()

C

int sockfd = socket(...);
int client_sockfd;
// ...
client_sockfd = accept(sockfd, ...);
shutdown(sockfd, 2);
close(sockfd);
// ...
shutdown(client_sockfd, 2);
close(client_sockfd);

As shown in the above code, can we use only one socket to complete the accepting end of the entire network programming? Is there any problem with this? (At least I didn't have any problems writing the program like this myself)

答案1

得分: 3

你总是创建两个套接字:服务器套接字和第一个接受的客户端套接字。何时关闭它们取决于您。

在Python中同时使用相同的名称仍然会关闭服务器套接字(最终)因为对象引用计数降为零,但在C中会造成套接字泄漏。

英文:

You are always creating two sockets: the server socket and the first accepted client socket. When you close them is up to you.

Using the same name for both in Python will still close the server socket (eventually) because the object reference count goes to zero, but in C you leak the socket.

答案2

得分: 2

> 那我们可以跳过创建client_sockfd变量的任务吗?

对于面向连接的协议,例如TCP,不行。在这种服务的接收端涉及的两个套接字是不同类型的,具有不同的用途,都是必需的。

在C中,您通过socket()函数创建并与accept()函数一起使用的套接字通常称为“服务器套接字”。它的工作是等待传入的连接请求,并在接受请求时为与该请求的远程对等方进行通信准备一个端点。通过成功调用accept()获得的第二个(第三个和第四个……)套接字表示结果端点。

您可以使用服务器套接字来接受连接,可能同时具有多个活动连接,并且可以使用每个其他套接字(如果您喜欢,“对等套接字”)与特定客户端进行通信。关闭对等套接字会终止与关联远程对等方的连接。关闭服务器套接字会使系统停止在其地址/端口上接受新的连接。

您提出了这种替代方法:
> c &gt; int sockfd; &gt; struct sockaddr_in server, client; &gt; socklen_t client_size = sizeof(client); &gt; sockfd = socket(...); &gt; // ... &gt; sockfd = accept(sockfd, (struct sockaddr *)&amp;client, &amp;client_size); &gt;
从技术上讲,这并不是错误的,但一旦将accept()的结果分配给变量sockfd,您将不再能够访问服务器套接字(假设您没有将其文件描述符存储在另一个变量中,这将使问题无效)。这是资源泄漏。此外,它会阻止您在指定的地址/端口上接受任何后续连接。在进程终止之前(如果有的话),您甚至都无法为该端口创建新的服务器套接字,因为现有的套接字会妨碍此操作。


所有这些都对于数据报导向的套接字都是不同的——没有连接要accept(),也没有这种协议的服务器套接字和对等套接字之间的固有区别。但根据您的示例代码中的accept()调用,这似乎不是您所询问的内容。

英文:

> So can we skip the task of creating the client_sockfd variable?

For connection-oriented protocols such as TCP, no. The two sockets involved on the receiving side of such a service are of different kinds and serve different purposes, both required.

The socket that (in C) you create via the socket() function and use with the accept() function is often called a "server socket". It's job is to wait for incoming connection requests, and when it accepts one, to prepare an endpoint for communication with that request's remote peer. The resulting endpoint is represented by the second (and third, and fourth ...) socket, obtained via successful calls to accept().

You use the server socket to accept connections, potentially having multiple active connections at the same time, and you use each of the others ("peer sockets", if you like) to communicate with a specific client. Closing a peer socket terminates the connection with the associated remote peer. Closing the server socket makes the system stop accepting new connections at its address / port.

You propose this alternative:
>
&gt; int sockfd;
&gt; struct sockaddr_in server, client;
&gt; socklen_t client_size = sizeof(client);
&gt; sockfd = socket(...);
&gt; // ...
&gt; sockfd = accept(sockfd, (struct sockaddr *)&amp;client, &amp;client_size);
&gt;

That's not technically wrong, but as soon as you assign the result of accept() to variable sockfd, you no longer have access to the server socket (supposing you did not store its file descriptor in another variable, which would moot the question). This is a resource leak. Moreover, it prevents you from accepting any subsequent connections at the designated address / port. Until the process terminates (if then), you will not even be able to create a new server socket for that port, as the existing one will be in the way.


All of this is different for datagram-oriented sockets -- there are no connections to accept(), and no inherent distinction between server sockets and peer sockets for such protocols. But based on the appearance of accept() calls in your example code, that's not what you are asking about.

答案3

得分: 0

In your first example:

from socket import *
sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
# ...
client_sockfd.close()
sockfd.close()

sockfd 是监听器的描述符。它可以被重新使用。
在关闭 client_sockfd 后,您可以再次执行 accept

例如:

from socket import *
sockfd = socket(...)
while not is_finished:
   client_sockfd, addr = sockfd.accept()
   # ...
   client_sockfd.close()
sockfd.close()

您可以接受多个套接字(存储在不同的 fd 变量中),并与多个客户端进行通信。但这需要一些并发编程。

英文:

In your first example

from socket import *
sockfd = socket(...)
# ...
client_sockfd, addr = sockfd.accept()
# ...
client_sockfd.close()
sockfd.close()

sockfd is the descriptor for the listener. It can be re-used.
After closing client_sockfd, you can accept again.

E.g.

from socket import *
sockfd = socket(...)
while not is_finished:
   client_sockfd, addr = sockfd.accept()
   # ...
   client_sockfd.close()
sockfd.close()

You can accept more than one socket (into different fd variables), and talk with multiple clients. However, this requires some concurrent programming.

答案4

得分: 0

Sure, here's the translated part without the code:

我不确定是否有一个“问题”,但似乎有必要解释正在发生的事情:

当你调用 sockfd.accept() 时,它会阻塞,直到有一个连接进来。一旦有连接进来,它会返回另一个表示该连接的套接字,可以用于发送和接收连接上的数据。多次调用 socket.close() 的原因在于,在你的第一个示例中,client_sockfd.close() 仅关闭连接。你仍然可以再次调用 sockfd.accept() 来接收另一个连接,而许多套接字服务器在while循环中使用 socket.accept()。调用 sockfd.close() 通常会关闭 sockfd,通常在不需要进行更多连接(对 sockfd.accept() 的调用)时才会关闭。

英文:

I'm not sure if there is a "problem", but it seems relevant to explain whats going on here:

When you call sockfd.accept() it blocks until a connection comes in. When one does come in it returns another socket which "represents" the connection, and can be used to send and receive data on the connection. The reason for the multiple calls to socket.close() is that in your first example client_sockfd.close() only closes the connection. You can still call sockfd.accept() again to receive another connection, and many socket servers use socket.accept() in a while loop. Calling sockfd.close() will close sockfd, usually when no further connections (calls to sockfd.accept()) need to be made.

huangapple
  • 本文由 发表于 2023年5月11日 00:39:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76220790.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定