文章目录1、预备知识1.1 网络字节序1.2 `客户端`/`服务器`模型2、编程接口 BSD Socket2.1 Socket是什么2.2 基本的 Socket 编程接口2.2.1 Socket API 概览(1)socket():创建 socket(2)bind():(服务器) 绑定 socket,绑定地址和端口(3)listen():(服务器) 监听 socket ,设置 Socket 为监听模式(4)accept():(服务器) 接受(客户端)连接(5)connect():(客户端) 连接服务器3、面向连接的 Socket:C/S模型-TCP数据传输的过程:3.1 server3.2 client4、面向无连接的 Socket:C/S模型-UDP4.1 server4.2 client参考博客:https://www.jianshu.com/p/ca0bbd8700ceSocket 这个词可以表示很多概念:概念类别描述1在TCP/IP协议中,【IP地址+TCP或UDP端口号】唯一标识网络通讯中的一个进程,IP地址+端口号就称为 Socket2在TCP协议中,建立连接的两个进程各自有一个 Socket 来标识,那么这两个Socket 组成的socket pair就唯一标识一个连接。Socket 本身有 插座 的意思,因此用来描述网络连接的一对一关系。3TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口 称为Socket API。1、预备知识1.1 网络字节序在几乎所有的计算机上,多字节的对象,都被表示为连续的字节序列。数据的高字节保存在 内存的低地址,称为大端模式(大端序);数据的高字节保存在 内存的高地址,称为小端模式(小端序)。0x12345678 这样一个 32 位整数在内存中需要占用四个字节,这四个字节的地址会递增。若随着地址增加,按照 0x12、0x34、0x56 和 0x78 这样的顺序存入内存,就称为大端序;反之,若随着地址增加,按照 0x78、0x56、0x34、0x12 的顺序存入内存,就称为小端序。大端序和小端序内存布局示意图:在网络应用中,字节序是一个必须考虑的因素,因为不同机器类型可能采用不同标准的字节序,所以均须按照网络标准转化。网络传输的标准叫做网络字节序,实际上是大端序。而我们常用的 X86都是小端序,ARM 的字节序实际上是可配置的,但是一般都配置为小端。在网络编程中不应该假设自己程序运行的主机的字节序,应当使用htonl/htons/ntohs/ntohl之类的函数来在网络字节序和主机字节序之间进行转换。#includearpa/inet.huint32_thtonl(uint32_thostlong);//host to net (long)uint16_thtons(uint16_thostshort);//host to net (short)uint32_tntohl(uint32_tnetlong);//net to host (long)uint16_tntohs(uint16_tnetshort);//net to host (short)其中h代表host,就是本地主机的表示形式;n代表network,表示网络上传输的字节序;s和l代表类型short和long。1.2客户端/服务器模型网络上进行通信的各端点,大部分都是遵循客户端/服务器模型的。一般来说,服务器端具有以下特征:序号特征1被动通信2始终等待来自客户端的请求3自己参与通信的网络接口和端口必须确定4处理客户端的请求后,将结果(响应)返回给客户端客户端的特征如下:序号特征1主动通信2需要发起请求3自己参与通信的网络接口和端口可以不确定4发起请求后,需要等待服务器回应结果服务器可以是有状态的,也可以是无状态的(Stateless),无状态的服务器不会保留两个请求之间的任何信息,而有状态的服务器会记住请求之间的信息。实际上的服务器一般都能同时并发处理多个客户端的请求。一个简单的客户机/服务器通信过程如图:2、编程接口 BSD Socket2.1 Socket是什么TCP/IP协议 存在于OS中,网络服务通过 OS 提供,在OS中增加支持TCP/IP的系统调用——Berkeley套接字,如socket,connect,send,recv等。网络传输概貌:Socket 是应用层与TCP/IP协议族通信的中间软件抽象层:Socket 起源于Unix,而Unix/Linux 基本哲学之一就是一切皆文件,都可以用“打开open – 读写write/read – 关闭close”模式来操作。Socket 就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。Socket是应用层与TCP/IP协议族 通信的中间软件抽象层,它是一组接口。在设计模式中,Socket 其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在 Socket 接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。注意:其实 Socket 也没有层的概念,它只是一个facade设计模式的应用,让编程变的更简单。是一个软件抽象层。在网络编程中,大量用的都是通过Socket 实现的。2.2 基本的 Socket 编程接口现在的网络编程接口通常是 Socket。BSD Socket 是事实上的网络应用编程接口标准(API),其它编程语言往往也使用和这套用 C 写成的 Socket 类似的接口。用 Socket 能够实现网络上的不同主机之间或同一主机的不同对象之间的数据通信。所以,现在 Socket 已经是一类通用通信接口的集合。2.2.1 Socket API 概览服务器端 先创建socket(),然后与端口绑定bind(),对端口进行监听listen(),调用accept()阻塞,等待客户端连接。在这时如果有个客户端初始化一个 socket(),然后连接服务器 connect(),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。这些接口的实现都是内核来完成。具体如何实现,可以看看 Linux内核。序号函数原型描述1intsocket(int domain,int type,int protocol)创建 Socket2intbind(intsocket,const struct sockaddr*address,socklentaddress_len)绑定地址和端口3intlisten(int socket,int backlog)设置 Socket 为监听模式4intaccept(int socket,struct sockaddr*restrict address,socklen_t*restrict address_len)接受连接5intconnect(int socket,const struct sockaddr*address,socklentaddress_len)连接服务器(1)socket():创建 socket在进行 Socket 通信之前,一般调用 socke(2) 函数来创建一个 Socket 通信端点。socket() 打开一个网络通讯端口,如果成功的话,就像 open() 一样返回一个文件描述符fd,应用程序可以像读写文件一样用read() / write()在网络上收发数据,如果 socket() 调用出错则返回-1。对于IPv4,domain参数指定为 AF_INET。对于TCP协议,type 参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则 type 参数指定为SOCK_DGRAM,表示面向数据报的传输协议。socket(2)函数原型如下:#includesys/types.h#includesys/socket.hintsocket(intdomain,inttype,intprotocol);序号参数含义1domain地址类型:(1)AF_INET(IPv4)(2)AF_INET6(IPv6)2type协议类型:(1)SOCK_STREAM(面向连接)(2)SOCK_DGRAM(非连接)3protocol默认填0如果建立套接字成功,返回一个新的文件描述符fd,失败则返回-1,设置errno。这个函数可能发生的错误:序号errno 值错误含义1EPROTONOSUPPORT参数 domain 指定的类型不支持参数 type 或 protocol 指定的协议2ENFILE核心内存不足,无法建立新的 socket 结构3EMFILE进程文件表溢出,无法再建立新的套接字4EACCESS权限不足,无法建立 type 或 protocol 指定的协议5ENOBUFS、ENOMEM内存不足6EINVAL参数不合法(invalid)序号类型示例1创建 TCP Socketsockfd=socket(AF_INET, SOCK_STREAM, 0);2创建 UDP Socketsockfd=socket(AF_INET, SOCK_DGRAM, 0);实际程序中,应该先检查返回值sockfd有效后,再使用。(2)bind():(服务器) 绑定 socket,绑定地址和端口创建了 Socket 后,可以调用 bind(2) 函数来将这个 Socket 绑定到特定的地址和端口上来进行通信。函数原型如下:#includesys/types.h/* See NOTES */#includesys/socket.hintbind(intsockfd,conststruct