1、为何要学习socket?web
咱们打开浏览器浏览网页时,浏览器的进程怎么与web服务器通讯的?咱们用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通讯?这些都得靠socket。本地的进程间通讯(IPC)有不少种方式,但能够总结为下面4类:编程
但这些都不是本文的主题!咱们要讨论的是网络中进程之间如何通讯?首要解决的问题是如何惟一标识一个进程,不然通讯无从谈起!在本地能够经过进程PID来惟一标识一个进程,可是在网络中这是行不通的。其实TCP/IP协议族已经帮咱们解决了这个问题,网络层的“ip地址”能够惟一标识网络中的主机,而传输层的“协议+端口”能够惟一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就能够标识网络的进程了,网络中的进程通讯就能够利用这个标志与其它进程进行交互。浏览器
使用TCP/IP协议的应用程序一般采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通讯。就目前而言,几乎全部的应用程序都是采用socket,而如今又是网络时代,网络中进程通讯是无处不在,这就是我为何说“一切皆socket”服务器
2、什么事Socket? 网络
想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何再它们之间传输的标准。从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族。不一样于ISO模型的七个分层,TCP/IP协议参考模型把全部的TCP/IP系列协议归类到四个抽象层中dom
应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等socket
传输层:TCP,UDP函数
网络层:IP,ICMP,OSPF,EIGRP,IGMP学习
数据链路层:SLIP,CSLIP,PPP,MTUspa
每一抽象层创建在低一层提供的服务上,而且为高一层提供服务,看起来大概是这样子的
socket
咱们知道两个进程若是须要进行通信最基本的一个前提能可以惟一的标示一个进程,在本地进程通信中咱们可使用PID来惟一标示一个进程,但PID只在本地惟一,网络中的两个进程PID冲突概率很大,这时候咱们须要另辟它径了,咱们知道IP层的ip地址能够惟一标示主机,而TCP层协议和端口号能够惟一标示主机的一个进程,这样咱们能够利用ip地址+协议+端口号惟一标示网络中的一个进程。
可以惟一标示网络中的进程后,它们就能够利用socket进行通讯了,什么是socket呢?咱们常常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操做抽象为几个简单的接口供应用层调用已实现进程在网络中通讯。
socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在创建链接打开后,能够向本身文件写入内容供对方读取或者读取对方内容,通信结束时关闭文件。
3、socket通讯流程
socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通信的socket为例,其交互流程大概是这样子的
服务器根据地址类型(ipv4,ipv6)、socket类型、协议建立socket
服务器为socket绑定ip地址和端口号
服务器socket监听端口号请求,随时准备接收客户端发来的链接,这时候服务器的socket并无被打开
客户端建立socket
客户端打开socket,根据服务器ip地址和端口号试图链接服务器socket
服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回链接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回链接信息后才返回,开始接收下一个客户端谅解请求
客户端链接成功,向服务器发送链接状态信息
服务器accept方法返回,链接成功
客户端向socket写入信息
服务器读取信息
客户端关闭
服务器端关闭
4、三次握手
在TCP/IP协议中,TCP协议经过三次握手创建一个可靠的链接
第一次握手:客户端尝试链接服务器,向服务器发送syn包(同步序列编号Synchronize Sequence Numbers),syn=j,客户端进入SYN_SEND状态等待服务器确认
第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
5、socket的基本操做
既然socket是“open—write/read—close”模式的一种实现,那么socket就提供了这些操做对应的函数接口。下面以TCP为例,介绍几个基本的socket接口函数。
(1)socket()函数
socket函数对应于普通文件的打开操做。普通文件的打开操做返回一个文件描述字,而socket()用于建立一个socket描述符(socket descriptor),它惟一标识一个socket。这个socket描述字跟文件描述字同样,后续的操做都有用到它,把它做为参数,经过它来进行一些读写操做。正如能够给fopen的传入不一样参数值,以打开不一样的文件。建立socket的时候,也能够指定不一样的参数建立不一样的socket描述符,socket函数的三个参数分别为:
注意:并非上面的type和protocol能够随意组合的,如SOCK_STREAM不能够跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。
当咱们调用socket建立一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。若是想要给它赋值一个地址,就必须调用bind()函数,不然就当调用connect()、listen()时系统会自动随机分配一个端口。
(2)bind()函数
正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。
(3)listen()、connect()函数
若是做为一个服务器,在调用socket()、bind()以后就会调用listen()来监听这个socket,若是客户端这时调用connect()发出链接请求,服务器端就会接收到这个请求。
(4)accept()函数
TCP服务器端依次调用socket()、bind()、listen()以后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()以后就想TCP服务器发送了一个链接请求。TCP服务器监听到这个请求以后,就会调用accept()函数取接收请求,这样链接就创建好了。以后就能够开始网络I/O操做了,即类同于普通文件的读写I/O操做
(5)read()、write()等函数
万事具有只欠东风,至此服务器与客户已经创建好链接了。能够调用网络I/O进行读写操做了,即实现了网咯中不一样进程之间的通讯!网络I/O操做有下面几组:
我推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数
(6)close()函数
在服务器与客户端创建链接以后,会进行一些读写操做,完成了读写操做就要关闭相应的socket描述字,比如操做完打开的文件要调用fclose关闭打开的文件。
6、socket实例
代码下载http://files.cnblogs.com/files/qtiger/SocketExmple.zip