socket 编程入门教程(一)TCP server 端:5、创建监听嵌套字

作者:龙飞



前面一小节,我们已经写出了TcpServer的构造函数。这个函数的实际作用,就是创建了listen socket(监听嵌套字)。这一节,我们来具体分析这个创建的过程。



socket和sockaddr的创建是可以相互独立的



在函数中,我们首先通过socket()系统调用创建了listenSock,然后通过为结构体赋值的方法具体定义了服务器端的sockaddr。(memset()函数的作用是把某个内存段的空间设定为某值,这里是清零。)其他的概念已经在前一小节讲完了。这里需要补充的是说明宏定义INADDR_ANY。这里的意思是使用本机所有可用的IP地址。当然,如果你机器绑定了多个IP地址,你也可以指定使用哪一个。



数据流简易模型(SOCK_STREAM)



我们的例子以电话做的比喻,实际上,socket stream模型不完全类似电话,它至少有以下这些特点:

1、一种持续性的连接。这点跟电话是类似的,也可以想象成流动着液体的水管。一旦断开,这种流动就会中断。

2、数据包的发送实际上是非连续的。这个世界上有什么事物是真正的线性连续的?呵呵,扯远了,这貌似一个哲学问题。我们仅仅需要知道的是,一个数据包不可能是无限大的,所以,总是一个小数据包一个小数据包这样的发送的。这一点,又有点像邮包的传递。这些数据包到达与否,到达的先后次序本身是无法保证的,即是说,是IP协议无法保证的。但是stream形式的TCP协议,在IP之上,做了一定到达和到达顺序的保证。

3、传送管道实际上是非封闭的。要不干嘛叫“网络”-_-!!!。我们之所以能保证数据包的“定点”传送,完全是依靠每个数据包都自带了目的地址信息。

由此可见,虽然socket和sockaddr可以分别创建,并无依赖关系。但是在实际使用的时候,一个socket至少会绑定一个本机的sockaddr,没有自己的“地址信息”,就不能接受到网络上的数据包(至少在TCP协议里面是这样的)。



socket与本机sockaddr的绑定



有时候绑定是系统的任务,特别是当你不需要知道自己的IP地址和所使用的端口号的时候。但是,我们现在是建立服务器,你必须告诉客户端你的连接信息:IP和Port。所以,我们需要指明IP和Port,然后进行绑定。
intbind(intsocket,structsockaddrlocalAddress, unsignedintaddressLength);
作为C++的程序员,也许你会觉得这个函数很不友好,它似乎更应该写成:
intbind_cpp_style(intsocket,constsockaddr&localAddress);
我们需要通过函数原型指明两点:

1、我们仅仅使用sockaddr结构的数据,但并不会对原有的数据进行修改;

2、我们使用的是完整的结构体,而不仅仅是这个结构体的指针。(很显然光用指针是无法说明结构体大小的)

幸运的是,在Linux的实现中,这个函数已经被写为:
#include<sys/socket.h>



/
Give the socket FD the local address ADDR (which is LEN bytes long)./

externintbind (int__fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)

__THROW;

看到亲切的const,我们就知道这个指针带入是没有“副作用”的。



监听:listen()



stream流模型形式上是一种“持续性”的连接,这就是要求信息的流动是“可来可去”的。也就是说,stream流的socket除了绑定本机的sockaddr,还应该拥有对方sockaddr的信息。在listen()中,这“对方的sockaddr”就可以不是某一个特定的sockaddr。实际上,listen socket的目的是准备被动的接受来自“所有”sockaddr的请求。所以,listen()反而就不能指定某个特定的sockaddr。
intlisten(intsocket,intqueueLimit);
其中第二个参数是等待队列的限制,一般设置在5-20。Linux中实现为:
#include<sys/socket.h>



/
Prepare to accept connections on socket FD.

N connection requests will be queued before further requests are refused.

Returns 0 on success, -1 for errors.
*/

externintlisten (int__fd,int__n) __THROW;
完成了这一步,回到我们的例子,就像是让你小弟在电话机前做好了接电话的准备工作。需要再次强调的是,这些行为仅仅是改变了socket的状态,实际上我想强调的是,为什么这些函数不会造成block(阻塞)的原因。(block的概念以后再解释)
原文链接: https://www.cnblogs.com/yin-jingyu/archive/2012/06/06/2537554.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/52149

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午3:38
下一篇 2023年2月9日 上午3:39

相关推荐