您的位置:首页 > 理论基础 > 计算机网络

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

2013-10-15 13:06 561 查看


前面一小节,我们已经写出了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,然后进行绑定。

int bind(int socket, struct sockaddr* localAddress, unsigned int addressLength);
作为C++的程序员,也许你会觉得这个函数很不友好,它似乎更应该写成:

int bind_cpp_style(int socket, const sockaddr& localAddress);
我们需要通过函数原型指明两点:

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

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

幸运的是,在Linux的实现中,这个函数已经被写为:

#include <sys/socket.h>

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

extern int bind (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。

int listen(int socket, int queueLimit);
其中第二个参数是等待队列的限制,一般设置在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. */

extern int listen (int __fd, int __n) __THROW;
完成了这一步,回到我们的例子,就像是让你小弟在电话机前做好了接电话的准备工作。需要再次强调的是,这些行为仅仅是改变了socket的状态,实际上我 想强调的是,为什么这些函数不会造成block(阻塞)的原因。(block的概念以后再解释)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐