Chinaunix首页 | 论坛 | 博客
  • 博客访问: 78203
  • 博文数量: 15
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 117
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-25 12:01
文章分类

全部博文(15)

文章存档

2017年(1)

2016年(1)

2015年(13)

我的朋友

分类: LINUX

2015-04-03 20:28:05

一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识: 

(协议,本地地址,本地端口号,远地地址,远地端口号) 这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接

tcp/ip 协议共用于任何操作系统上,而socket则是建立在这种协议之上的最为广泛应用的协议。
下面是tcp协议的具体工作流程

listen函数

摘要:listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。
在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

listen函数在一般在调用bind之后-调用accept之前调用,它的函数原型是:

intlisten(int sockfd, int backlog)

参数sockfd

被listen函数作用的套接字,sockfd之前由socket函数返回。在被socket函数返回的套接字fd之时,它是一个主动连接的套接字,也就是此时系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接,然后在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接。由于系统默认时认为一个套接字是主动连接的,所以需要通过某种方式来告诉系统,用户进程通过系统调用listen来完成这件事。

参数backlog

这个参数涉及到一些网络的细节。进程处理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。

毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。

accept函数

摘要:accept()用来接受参数s的socket连接,它的函数原型是:

intaccept(int s,struct sockaddr * addr,int * addrlen)

服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。


listen只是创建监听套接字,3路握手并不是由listen函数来完成的。
listen只做两件事:
1,将socket创建的主动(默认)套接字转换成被动套接字,指示内核接受指向该套接字的连接请求
2,指定内核应该为相应套接字排队的最大连接数
accept仅仅是从监听套接字队列中取出完成握手的连接套接字,至于阻塞的唤醒也是由内核自动完成的
accept取出套接字的队列存放的全是已经完成连接的套接字,对于监听套接字,一般会有两个队列,未完成连接套接字和已完成连接套接字,当请求到达时,新建套接字会被存放在未完成中,3路握手完毕就会被转移到已完成队列里,accept就是从已完成队列里取。这两个队列的维护和3路握手都是由内核自动完成,不需要服务器进程去插手

   listen只是把套接字从主动变为被动,并限制链接数;剩下的问题就是accept的,它会检测的;
listen意思是监听:但是它不是一直在监听,accept才是
三次握手连接示意图



四次握手断开连接示意图




阅读(2618) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~