何时关闭套接字TCP

时间:2018-07-14 17:29:30

标签: sockets tcp

我正在使用GPS跟踪器。我正在通过套接字监听gps跟踪器设备。目前,我正在同时收听20台设备。我在想几个问题

最初,我正在打开一个套接字,并在读取它后关闭了该循环。我正在按时从设备接收数据。问题在于,当设备增加时,来自多个设备的侦听时间会变慢,然后不再是实时的

然后,我选择在打开插座后不关闭插座。它变得实时并按时从每个设备获得响应,但是现在当我通过运行此命令检查进程时

 sudo netstat -tulnap | grep :8153

现在总共建立了750个连接。所以我想我可能做错了什么?

所以我想知道如果一次要从所有设备接收数据怎么办?还是有更好的方法来实现它?如果有人能引导我朝正确的方向前进,将不胜感激。

注意:我的设备可能会扩展到20到20,000个设备,因此您提供的解决方案应该能够实时监听任意数量的设备中的数据

提前谢谢

1 个答案:

答案 0 :(得分:3)

规则是:使用完毕后关闭套接字; OTOH如果您打算将来继续通过该套接字接收/发送数据,请保持打开状态,以便进行操作。判断套接字保持打开状态(先关闭套接字,然后再重新打开新的TCP连接)是一种判断调用,它取决于您的程序要完成的工作。

听起来您的程序可能正遭受“套接字泄漏”的困扰,在某些情况下,您的程序忘记了在不再打算使用的套接字上调用close();而且您的程序还在继续创建新的套接字。在这种情况下,这些开放但被遗忘的套接字将随着时间的流逝而建立,最终您的程序将耗尽资源,并且无法创建更多套接字。这是一件坏事。

您没有说您使用的是哪种语言,但是如果您使用C ++编程,一种避免套接字泄漏的简单方法是将每个套接字包装到一个套接字持有对象中:

class SocketHolder
{
public:
   SocketHolder(int socketfd) : _fd(fd) {/* empty */}
   ~SocketHolder() {if (_fd >= 0) close(fd);}

   int GetSocketFD() const {return _fd;}

private:
   SocketHolder(const SocketHolder &);  // private and unimplemented (to prevent accidental copying of SocketHolder objects)

   int _fd;
};

...,然后每当调用socket()/ accept()/ etc创建新的套接字FD时,立即将其移交给由智能指针保存的SocketHolder对象,例如:

int s = socket();
std::shared_ptr<SocketHolder> holder(new SocketHolder(s));

...并修改程序以存储和/或传递std::shared_ptr<SocketHolder>对象而不是int套接字值。

这样做的好处是,完成此操作后,您将不再需要记住在适当的时间显式调用close(s),因为当其SocketHolder对象成为对象时,它将自动为您调用删除,SocketHolder对象将在最后一个引用它的智能指针消失后自动删除。由于close()调用现在无需程序员费力就可以进行,因此套接字泄漏的可能性要小得多。

问题的另一个可能根源是,即使关闭了操作系统,操作系统(默认情况下)也将在短时间内在内存中保留最近关闭的TCP连接的记录;这样做可以帮助操作系统确保在关闭套接字之前发送给套接字的任何数据都可以传递,并且还可以帮助操作系统避免误解将来的TCP数据包。但是,这确实意味着在关闭TCP套接字后,TCP套接字记录可以在短时间内徘徊。如果这对您来说是个问题,您可以通过设置SO_LINGER套接字选项来解决此问题,如here所述。

如果您要保持与数十个或数百个设备同时打开的TCP连接,那就很好了;您可以这样做,并使用select()poll()epoll()kqueue()或旨在立即处理多个套接字的类似API在它们之间进行多路复用。以我的经验,从长远来看,使用非阻塞I / O更为简单,因为它避免了一个非常慢(或发生故障)的客户端设备挂断整个服务器的可能性。

如果确实需要支持数千个同时进行的TCP连接,而不是几十个或数百个,则可能会遇到一些扩展问题。您可能需要阅读The C10K Problem,这是一篇过时但仍能提供有用信息的文章,介绍了各种方法来处理这种大小的连接负载。

正如paulsm4所述,另一种替代方法可能是使用UDP代替TCP进行通信。这样做的好处是您只需要创建一个套接字(可用于与任何数量的设备进行通信),而不是每个设备一个套接字。一些缺点包括以下事实:通常很难在Internet上路由UDP数据包(防火墙默认情况下倾向于拒绝传入的UDP数据包),并且UDP数据包没有任何传递或排序保证了TCP流的方式。当然,如果您的设备仅讲TCP,那么UDP就不是您的选择。