为什么多个客户端可以连接服务器的同个端口?

平时我们使用ServerSocket指定了某个端口(例如8080),然后多个客户端连接上socket之后就都用这个8080端口和服务器端通讯。或者http服务器使用80端口也是和多个浏览器进行连接通讯。为什么可以这样呢?操作系统的进程在同个端口的多个连接是如何进行分辨的?


译文

我们这里讲Socket连接:
1. 端口只是一个数字辨识,不是真正的物理端口;
2. 一个Socket连接的主键(即不同socket之间的区分)是由一个五元组{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL}组成,即{源地址,源端口,目标地址,目标端口,协议}组成,那些说四元组不包含协议的说法是错误的。
3. 一个进程可以拥有多个socket连接。

例子一、两个客户端连接在同个服务器的同个端口80,即有两个socket连接:
- socket1 {SRC-A, 100, DEST-X,80, TCP}
- socket2{SRC-B, 100, DEST-X,80, TCP}
主机A和主机B的地址不同,两台主机同时连接到服务器X的80端口。服务器要怎么处理这个连接是它的事,我们要理解的是为什么一个主机同个端口能监听多个客户端Socket连接。

解释:
1. 是因为两个客户端的IP不同,服务器能识别出不同的Socket;
2. 即使IP地址相同,端口不同,服务器也能够分辨;
3. 只要服务器知道收到的请求和哪个socket相关,那么它就能使用这个socket正确地回复那个客户端;
4. 如果对于不同的socket需要不同的端口,那么不仅仅浪费服务器资源,而且每次客户端连接上serverSocket之后还要另外分配新的端口和客户端通信。没必要。

例子二、不同的进程可以监听同一个端口。

  1. 因此在服务器的两个使用不同协议的进程可以监听同一个端口。
  2. 如果一个socket的辨识只是四元组不包括协议{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT},那么不同进程是不可能同时监听同一个端口的。没有协议的话一个客户端连接到同一台某个有两个进程监听端口的服务器,那么就没有什么机制可以确定客户端是要连接哪一个进程了。

操作系统(特别是UNIX)中,子进程能够继承父进程的所有文件描述File-descriptors (FD),因此父进程A中监听着的所有socket,也可以被进程的所有子进程A1,A2监听。但是不同进程B是不能监听同一个端口的。

翻译自stackoverflow的第二个答案:
https://stackoverflow.com/questions/3329641/how-do-multiple-clients-connect-simultaneously-to-one-port-say-80-on-a-server


疑问

但是里面说了:
For example two unrelated clients (say one is using TCP and another is using UDP) can bind connect and communicate to the same server node and to the same port but they must be served by two different server-processes.

两个不同的客户端(一个使用tcp一个用udp)可以连接同一个服务器的同一个端口,但是需要两个不同的服务器进程。

我觉得是错的,所以我尝试了一下:

服务器:

    public static void main(String[] args) throws IOException {
        //很明显如下程序在同一个进程

        //udp使用5555端口
        DatagramSocket ds = new DatagramSocket(5555);
        byte[] buf = new byte[1024];
        DatagramPacket dp_receive = new DatagramPacket(buf, 1024);
        ds.receive(dp_receive);
        System.out.println("收到udp消息");
        System.out.println("客户端发送udp端口为" + dp_receive.getPort());

        //tcp使用5555端口
        ServerSocket serverSocket = new ServerSocket(5555);
        Socket socket = serverSocket.accept();
        System.out.println("tcp建立了连接");
        System.out.println("客户端发送tcp端口为" + socket.getPort());

    }

客户端:

    public static void main(String[] args) throws IOException, InterruptedException {
        //udp使用12345端口发出udp消息
        DatagramSocket ds = new DatagramSocket(12345);
        String str_send = "Hello";
        InetAddress loc = InetAddress.getLocalHost();
        //udp发送到服务器的5555端口
        DatagramPacket dp_send = new DatagramPacket(str_send.getBytes(), str_send.length(), loc, 5555);
        ds.send(dp_send);
        //tcp使用12345端口发送到服务器的5555端口
        Socket socket = new Socket("127.0.0.1", 5555, null, 12345);
    }

服务器输出:

收到udp消息
客户端发送udp端口为12345
tcp建立了连接
客户端发送tcp端口为12345

所以很明显,同个进程也可以通过不同的协议监听同一个端口。


总结

  1. 不同协议可以监听同一个端口(不管是不是在服务器的同个进程)
  2. 某个协议的进程可以监听多个客户端的连接,因为只要五元组不同进程就能分辨。
  3. 从上面的例子可以知道,客户端同个进程也可以在同个端口用不同的协议与客户端建立连接。
  • 28
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 在Qt中,可以使用QTcpServer类来创建一个服务器,它可以同时接受多个客户端连接。当有新的客户端连接时,可以通过QAbstractSocket类的派生类QTcpSocket来与客户端进行通信。 首先,我们需要实例化一个QTcpServer对象,然后通过调用其listen()函数来监听指定的IP地址和端口。例如: QTcpServer *server = new QTcpServer(this); if (!server->listen(QHostAddress::Any, 1234)) { qDebug() << "Server could not start: " << server->errorString(); } else { qDebug() << "Server started!"; } 当有新的客户端连接时,QTcpServer会发出newConnection()信号,可以通过连接该信号的槽函数来处理新的连接请求。在槽函数中,可以使用nextPendingConnection()函数来获取新的QTcpSocket对象,该对象可以用于与客户端进行通信。 例如: QObject::connect(server, &QTcpServer::newConnection, [=]() { QTcpSocket *clientSocket = server->nextPendingConnection(); qDebug() << "New client connected!"; }); 通过上述代码,在有新的客户端连接时,会打印"New client connected!"。 接下来,可以通过clientSocket对象来读取和写入数据,与客户端进行通信。例如,可以使用readyRead()信号来处理客户端发送的数据,并使用write()函数发送响应数据给客户端。 QObject::connect(clientSocket, &QTcpSocket::readyRead, [=]() { QByteArray data = clientSocket->readAll(); qDebug() << "Received data from client: " << data; // Send response to client clientSocket->write("Hello from server!"); }); 通过上述代码,在客户端发送数据时,会打印"Received data from client: "并显示接收的数据,并向客户端发送"Hello from server!"。 当需要断开与客户端连接时,可以使用disconnectFromHost()函数。 总结:在Qt中,可以通过QTcpServer类创建一个服务器,通过nextPendingConnection()函数获取客户端连接对象,再通过该对象与客户端进行通信并处理数据。通过连接newConnection()信号,可以实现多个客户端连接。 ### 回答2: 在Qt中,我们可以使用QTcpServer类来实现一个服务器连接多个客户端的功能。首先,我们创建一个QTcpServer的实例,并调用listen()函数来开始监听指定的端口。当有客户端连接服务器时,QTcpServer会自动创建一个新的QTcpSocket来处理与该客户端的通信。 为了连接多个客户端,我们可以使用一个容器(例如QList)来保存所有与客户端连接,每当有新的连接时,我们将其加入到容器中。当收到消息时,我们可以遍历容器中的所有连接,并向每个连接发送消息。 为了处理多个客户端连接请求,我们可以监听QTcpServer的newConnection()信号。当这个信号触发时,代表有新的客户端连接服务器。我们可以在这个信号的槽函数中使用nextPendingConnection()函数来获取与新客户端连接的套接字,并将其保存到容器中。 当给定的连接断开时,我们需要在容器中删除该连接。为了实现这个功能,我们可以利用QTcpSocket的disconnected()信号,该信号在连接断开时被触发。在这个信号的槽函数中,我们可以通过调用deleteLater()函数和从容器中删除该连接来释放相关资源。 总的来说,通过使用QTcpServer、QTcpSocket以及相关的信号和槽函数,我们可以在Qt中轻松地实现一个服务器连接多个客户端的网络应用。 ### 回答3: 在Qt中,我们可以使用QTcpServer类和QTcpSocket类来实现一个服务器连接多个客户端的功能。 首先,我们需要创建一个QTcpServer对象,并使用listen()函数来开始监听客户端连接。然后,我们可以使用newConnection()信号来接收客户端连接请求。 每当有新的客户端连接时,QTcpServer会自动触发newConnection()信号。我们可以在这个信号的槽函数中,创建一个新的QTcpSocket对象来处理与该客户端的通信。 创建新的QTcpSocket对象后,我们需要连接相应的信号和槽函数来处理与客户端的通信。常见的信号有readyRead()和disconnected(),分别表示接收到客户端发送的数据和客户端断开连接。我们可以在readyRead()信号的槽函数中读取客户端发送的数据,然后进行相应的处理。在disconnected()信号的槽函数中,我们可以释放相应的资源,并将客户端相关的QTcpSocket对象删除。 对于有多个客户端连接的情况,我们可以使用QList或QMap来存储所有的QTcpSocket对象,并通过客户端的唯一标识符来区分和管理每个客户端连接。 需要注意的是,在处理与客户端的通信时,我们可能会遇到多线程或多线程事件循环的情况。因此,为了避免多个客户端之间的数据混乱和冲突,我们可能需要使用互斥锁或信号槽来进行线程间的同步和通信。 以上就是使用Qt实现一个服务器连接多个客户端的基本步骤。通过合理的设计和编码,我们可以实现一个高效、稳定和可扩展的服务器系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值