套接字
在前面我们讲了TCP/IP、TCP和UDP的一些基本知识,但是协议只有一套,而我们系统多个TCP连接或多个应用程序进程必须通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。
套接字Socket看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。套接字Socket是连接应用程序和网络驱动程序的桥梁,套接字Socket在应用程序中创建,通过绑定与网络驱动建立关系。此后,应用程序送给套接字Socket的数据,由套接字Socket交给网络驱动程序向网络上发送出去。计算机从网络上收到与该套接字Socket绑定IP地址和端口号相关的数据后,由网络驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据,网络应用程序就是这样通过Socket进行数据的发送与接收的。
操作系统区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。
套接字类型
常用的TCP/IP协议的套接字有三种:
流套接字(SOCK_STREAM)
流套接字用于提供面向连接、可靠的数据传输服务。看到这个我们想到了什么,是不是TCP
该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。
TCP(The Transmission Control Protocol)协议
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
数据报套接字(SOCK_DGRAM)
数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。
UDP(User Datagram Protocol)协议
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
原始套接字(SOCK_RAW)
原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW
原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。
socket编程接口
//创建socket文件描述符(TCP/UDP,客户端+服务器)
int socket(int domain,int type,int protocol);
//绑定端口号(TCP/UDP,服务器)
int bind(int socket,const struct sockaddr *address,socklen_t address_len);
//开始监听socket(TCP,服务器)
int listen(int socket,int backlog);
//接收请求(TCP,服务器)
int accept(int socket,struct sockaddr* address,socklen_t* address_len);
//建立连接(TCP,客户端)
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
套接字通信建立过程
———————————————————————————————————————————————
服务器端
socket == 创建服务器监听套接字
服务器应用程序用系统调用socket创建一个套接字。 它是系统分配给服务器进程的类似文件描述符的资源。
bind == 绑定服务器监听信息到套接字
服务器进程用系统调用bind命名套接字。 然后服务器进程就开始等待客户连接到这个命名套接字。
listen == 开始监听,接收客户端的TCP连接
accept 从listen所维护的队列中取出一条已连接的TCP,返回该连接的socket描述字
服务器通过系统调用accept来接受客户的连接。 accept会创建一个不同于命名套接字的新套接字来与这个特定客户进行通信,而命名套接字则被保留下来继续处理其他客户的连接请求。
注意listen和accept是面向连接的套接字才会有的,正常的无连接通信在bind之后,服务器就会阻塞一直到接收到客户端发来的数据
close == 关闭打开着的套接字
最后关闭套接字,关闭打开的套接字文件描述符号
TCP服务器
UDP服务器
客户端
socket == 创建客户端连接套接字
调用socket创建一个未命名套接字。
connect == 向指定服务器发起连接请求
调用connect与服务器建立连接,将服务器的命名套接字作为一个地址。
然后服务器客户端在连接socket描述字上进行消息通信