Socket编程之一个端口能建立多个TCP连接

15 篇文章 0 订阅
1 篇文章 0 订阅

唯一能够确定一个socket连接有4点

  1. 服务器的IP
  2. 服务器的Port
  3. 客户端的IP
  4. 客户端的Port

tomcat最多能建立多少个连接?tomcat作为服务端程序,一直在监听80端口,之前一直以为tomcat每接收到一个新的连接,都会创建一个新的socket,然后这个socket又会占用一个端口。但是事实上并不是这样的,肯定是会创建新的socket的,但是这个新创建的socket并不会占用新的端口。
那么问题来了,客户端发送的数据,服务器是怎么区分是哪个客户端?
关键就在于上面的4个点,标识一个socket的是上面的4个点,而不是单纯的一个本地ip和一个本地端口,所以tomcat每accpet到一个连接,都会创建一个新的socket连接,这个socket连接种包含了下面4个信息,假设现在tomcat的ip为12.1.11.11

服务器ip:12.1.11.11
服务器端口:80
客户端ip:213.32.1.2
客户端端口:80

由这4个信息标识一个唯一的socket,tomcat accept到的每一个连接的服务器ip和端口都是一样的,但是客户端的ip和端口是不一样的,根据唯一标识socket的4点,系统能正确的区分。

服务端的socket有什么特殊的?

其实就我们创建一个新的socket来说,他是没有什么特殊的,他就是一个未连接的socket,特殊的点在于socket.listen()方法

#include<sys/socket.h>
int listen(int sockfd, int backlog);

listen函数仅由TCP服务器调用,当socket函数创建一个套接口时,它被假设为一个主动套装口,也就是说,它是一个将调用connet发起连接的客户套接口。listen函数把一个未连接的套接口转换成一个被动套接口,指示内核应接受指向该套接口的连接请求。根据TCP状态转换图,调用listen导致套接口从CLOSED状态转换到LISTEN状态。
注意,在java中是没有listen()函数的,因为java帮我们进行了封装,使用了ServerSocket来专门代表监听的Socket。
运行下面这个简单的程序

public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocket serverSocket = new ServerSocket(21111);
    Thread.sleep(100000000);
}

在windows中我们就能通过netstat -ano来查看端口占用,可以发现21111正处于监听状态
在这里插入图片描述
我们查看Java中的ServerSocket类的构造函数
在这里插入图片描述
能够看到,其实这与我们的c语言中的listen()函数差不多,其也有一个backlog参数。
为了更好的理解backlog参数,我们必须认识到内核为任何一个给定的监听套接口维护两个队列:
1、未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些套接口处于SYN_RCVD状态。
2、已完成连接队列(completed connection queue),每个已完成TCP三路握手过程的客户对应其中一项。这些套接口处于ESTABLISHED状态。
当来自客户的SYN到达时,TCP在未完成连接队列中创建一个新项,然后响应以三路握手的第二个分节:服务器的SYN响应,其中稍带对客户SYN的ACK(即SYN+ACK)。这一项一直保留在未完成连接队列中,直到三路握手的第三个分节(客户对服务器SYN的ACK)到达或者该项超时为止(曾经源自Berkeley的实现为这些未完成连接的项设置的超时值为75秒)。如果三路握手正常完成,该项就从未完成连接队列移到已完成连接队列的队尾。当进程调用accept时,已完成连接队列中的队头项将返回给进程,或者如果该队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。

如果监听的线程释放掉监听用的SOCKET了,会影响之前通过这个监听SOCKET建立的TCP连接么?

这个问题的答案是不会的,利用ServerSocket建立的连接,即使是ServerSocket关闭了,这个连接依然还是存在,因为他们之间本身就没有任何关系了

测试代码,Server

public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocket serverSocket = new ServerSocket();
    serverSocket.bind(new InetSocketAddress(8080));
    Socket accept = serverSocket.accept();
    new Thread(() -> {
        try {
            OutputStream outputStream = accept.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            while (true) {
                outputStreamWriter.write(UUID.randomUUID().toString() + System.lineSeparator());
                outputStreamWriter.flush();
                Thread.sleep(1000);
                System.out.println("写了一个");
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    serverSocket.close();
    System.out.println("连接关闭");
    Thread.sleep(100000);
}

Client

public static void main(String[] args) throws IOException, InterruptedException {
    Socket socket = new Socket();
    socket.connect(new InetSocketAddress("localhost", 8080));
    InputStream in = socket.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    String msg;
    while ((msg = reader.readLine()) != null) {
        System.out.println("读了一个");
        System.out.println(msg);
    }
    System.out.println("dsadsa");
    Thread.sleep(100000);
}

运行这两个代码我们就能发现,即使是ServerSocket关闭,依然能继续通信
我们又利用netstat -ano命令来查看端口占用在这里插入图片描述在这里插入图片描述

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个服务器对多个客户端的MFC Socket编程示例(实现简单的即时通讯功能) 环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端的socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端的socket对象 ,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值