【问题标题】:Understanding multithread server/client prog in c了解c中的多线程服务器/客户端程序
【发布时间】:2014-02-23 18:39:43
【问题描述】:

我刚刚开始学习网络概念。

在这个多线程服务器/客户端program 中,最后有为服务器编写的代码来处理多个连接。我的问题是服务器如何处理同一个套接字和端口(8888)上的多个连接。一个套接字一次只能在一个端口上接受一个客户端,通过创建pthread_create(),线程在其中扮演什么角色?

谁能给我一个套接字、端口、线程的图形表示,这样我就清楚了。我读的越多,我就越困惑。

【问题讨论】:

    标签: c multithreading networking tcp


    【解决方案1】:

    服务器收到连接请求后,接受请求即可完成连接。

    已建立为服务器的套接字可以接受来自多个客户端的连接请求。服务器的原始套接字不会成为连接的一部分;相反,accept 会创建一个参与连接的新套接字。 accept 返回此套接字的描述符。服务器的原始套接字仍可用于侦听进一步的连接请求。

    在您的情况下,当使用accept 连接新客户端时,会为特定客户端创建新文件描述符。 pthread_create 使用此客户端文件描述符创建新线程并完成他们的工作。

    EDIT1:

    tcp 服务器中的每个连接由 4 元组(serverip、serverport、destip、destport)区分。服务器监听相同的端口和ip,当客户端从不同的ip或不同的端口连接时,它将是不同的连接。

    在你的情况下:

    • 服务器监听 ip 10.10.62.5 端口 8888。
    • 两个客户端尝试使用端口 8990 和 8991 进行连接
    • 客户端 ip 不同,因此 tcp 服务器将其视为不同的连接。
    • 然后accept系统调用将接受客户端连接并将客户端连接路由到新的文件描述符以进行进一步操作。
    • pthread_create 将为新的处理程序分配新的客户端文件描述符。

    EDIT2:

    从链接客户端程序中可用的代码可以看出,连接到服务器的 8888 端口。客户端也需要一个端口来连接服务器,你不是在程序中自己分配客户端的端口。客户端程序动态选择随机端口。这个随机端口与 8888 不同。通过使用这个随机端口客户端连接到服务器的 8888 端口。

    所以服务器和客户端端口会不同,这将是不同的连接。使用wireshark捕获数据包,然后进行分析以获得更多说明。

    【讨论】:

    • Sujin:是的,我知道accept() 返回代表客户端套接字的套接字描述符。但是服务器仍然如何在其套接字描述符上接受多个客户端。想象一下服务器套接字描述符(这里是 socket_desc 是 5678,两个客户端有套接字描述符(这里是 client_sock)作为 8990 和 8991。所以这意味着服务器 desc 5678 连接到客户端 8990 和 8991 并且也在同一个端口上(8888)。这怎么可能???我无法理解。
    • 你要从两个不同的源端口连接客户端,所以它会是不同的连接
    • 两种不同的连接方式?我想你对数字感到困惑。5678 是服务器描述符,8990 和 8991 是客户端描述符而不是端口。使用的端口是 htons 中的 8888(8888)。而且我仍然不明白使用线程的目的是什么,它实际上做了什么。pthread_create 就像 fork() 一样,意味着它将创建一个新的子进程,但是这个子进程与父程序共享相同的地址空间.so 不是称它为进程,而是称它为线程。是这样的吗??
    • 多个客户端如何尝试通过不同的端口进行连接。在客户端程序中明确提到了 8888
    • @ShikharDeep 您没有为客户端分配任何端口号,它是动态分配的。客户端说连接到 10.10.62.4 的 8888 端口。
    【解决方案2】:

    就像你卡在服务器端,不清楚服务器端 accept() 的功能是什么

    所以 accept() 函数将提取待处理连接队列中的第一个连接,创建一个与指定套接字具有相同套接字类型协议和地址族的新套接字,并为该套接字分配一个新的文件描述符。

    accept() 函数采用以下参数:

    套接字: 指定使用socket() 创建的套接字,已使用bind() 绑定到地址,并已成功调用listen()。

    地址: 可以是空指针,也可以是指向应返回连接套接字地址的 sockaddr 结构的指针。

    address_len: 指向一个 socklen_t 结构,它在输入上指定提供的 sockaddr 结构的长度,在输出上指定存储地址的长度。

    因此,虽然服务器 IP 和服务器端口在所有接受的连接中都是不变的,但客户端信息是允许它跟踪所有内容的原因。

    例如

    假设我们在 192.168.1.1:80 有一个服务器和两个客户端,171.0.0.1 和 171.0.0.2。

    171.0.0.1 在本地端口 1234 上打开一个连接并连接到服务器。现在服务器有一个套接字,标识如下:

    171.0.0.1:1234 - 192.168.1.1:80
    

    现在 171.0.0.2 在本地端口 5678 上打开一个连接并连接到服务器。现在服务器有两个套接字,标识如下:

    171.0.0.1:1234 - 192.168.1.1:80
    171.0.0.2:5678 - 192.168.1.1:80
    

    在服务器端为不同的客户端连接返回不同的描述符。

    【讨论】:

    • 171.0.0.2 如何在不同的端口 5678 上打开连接。根据程序(在链接中给出)。它使用端口 8888(在这种情况下)。所以我打开的所有客户端在新终端中(因为我在 localhost 上同时运行服务器和客户端)将使用 8888。您指定的服务器端口和客户端端口没有什么不同,但在服务器和客户端的程序中都使用 8888
    【解决方案3】:

    这就是典型的服务器行为,

    我们确实将套接字绑定到一个接口,这可以是一个特定的接口,也可以是所有接口 INADDR_ANY。

    Accept 是阻塞调用,它接受客户端请求,返回新的 sockfd 让你处理请求。

    您可以在有界套接字上看到 netstat 结果,您将能够看到服务器监听套接字上的 LISTEN、RECV、SEND 计数。

    你是对的,所有的客户端套接字都连接在服务器绑定的接口上

    您的客户端套接字文件描述符总数存在限制。

    要增加客户端数量,您可以设置“ulimit”。

    因此,除了服务器绑定的套接字之外,还会为每个客户端消息处理创建 N 个套接字。

    看一下 netstat 输出

    netstat -antp --> 用于 tcp 规定输出。

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 2015-01-09
      • 2019-04-18
      • 2016-01-10
      • 2014-12-21
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多