一、socket简介
百度定义:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket,又称为套接字。
linux下类似于文件描述符。
二、知识预备
1.网络中信息如何传递,如何使信息到达指定目的地
2.网络字节序和主机字节序的区别
3.TCP与UDP通信方式的区别(可靠性 连接方式 数据传递方式)
4.端口范围及IP地址分类
三、API(系统预定义编程接口)
TCP通讯:
服务器端:
socket创建:头文件 #include<sys/types.h> #include<sys/socket.h> 作用:创建一个socket文件描述符
函数原型: int socket(int domain,int type ,int protocol)
参数释义:domain 底层协议族(详细协议族分类可百度一下- . -) type 指定服务类型 主要有流服务与数据报服务 分别对应SOCK_STREAM SOCK_DGRAM值 protocol 前两个参数构成的协议集合下,再选择一个具体的协议,由于一般前两个参数已经确定了具体的协议 所以其一般值为0。
返回值:成功返回一个socket文件描述符,失败返回-1(类似文件描述符)
命名socket: 头文件 #include<sys/types.h> #include<sys/socket.h> 作用:将一个socket与socket地址绑定
创建socket时只是指定了其协议族,而并未指定出其协议族下实际的地址。当我们给出其实际的地址后 ,客户端才知道该连向哪个地址,而客户端地址由系统自动分配 ,故客户端不用bind来绑定一个地址,服务器端有记录。
函数原型:int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen)
参数释义:socket 即要绑定的socket文件描述符 my_addr 自己设置的socket地址 addrlen 自己设置的socket地址的长度
补充:const struct sockaddr结构体
sa_family 表示使用的地址族 sa_data 表示使用的地址的值
由于其记录端口号等比较麻烦,所以linux提供了专门的socket地址结构体 TCP/IP协议族有sockaddr_in 和sockaddr_in6 两个专用地址结构体,下面给出IPv4地址的结构体
参数含义如上图所示,结构体的内容需要手动指定,指定时需要注意的是sin_port以及sin_addr指定方法,由于网络字节序都是大端字节序(规定了字节序就可以有目标性的对指定地址向规定进行相应转换,而不必要先测主机字节序再来选择具体转换方法)而一般PC机是小端字节序,所以指定端口port时要注意进行字节序的转换。系统为我们提供了字节序转换API。
举个函数名的含义 htonl---host to network long 即将长整型主机字节序转换成网络字节序,其他的按此类方法记录即可
指定sin_addr时:由于系统存放我们熟悉的点分十进制的字符串时是转换成整型的二进制,所以我们需要对自定义的点分十进制式的地址进行转化,系统为我们提供了如下的地址转换API
通常使用第一个函数,将点分十进制字符串转换为网络字节序整数表示的IPv4地址 第二个将转换结果存在struct in_addr结构体中,第三个与第一个函数作用相反。
至此即可正确的完成socket的命名(绑定)
监听socket:头文件#incldue<sys/socket.h> 作用创建一个监听队列,以便客户端得以连接
函数原型:int listen(int sockfd,int backlog)
参数释义:sockfd socket文件描述符 backlog 表示处于*完全连接状态*的上限数量(即完成三次握手并没有被应用层获取(accept是从队列中获取完全连接的sockfd)的最大个数)
返回值:成功返回0,失败返回-1;
接受连接:头文件 #include<sys/types.h> #include<sys/socket.h>
函数原型:int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
参数释义:sockfd执行过listen系统调用的监听socket(书中说将执行过listen操作的socket称为监听socket,把ESTABLISHED(建立连接)状态的socket称为连接socket 此外还有断开连接CLOSE_WAIT状态) addr 获取被接收连接的远端socket地址(即客户端的socket地址,系统获取) addrlen 系统获取的远端socket地址的长度
返回值:成功返回一个新的连接socket,唯一标识了被接收的这个连接,失败返回-1;
注意:accept只是从监听队列中取出连接,而不论连接处于何种状态。
数据读写: 作用类似于文件读写操作 flag参数提供控制 这里不研究这个 一般设为0;
注意:当数据量大于一次读空间大小时系统的操作是怎样的(TCP与UDP的一点重要区别 ) 这里简单提出TCP通信会维护一个输入输出缓冲区,不会导致溢出的数据部分被丢弃。
关闭连接:关闭该连接对应的socket
注意点与关闭文件一样:1.关闭只是使引用计数减一,直至为零才真正关闭 2.fork中父子进程都应该执行close操作 否则无法真正关闭该文件。
客户端:(无bind listen操作,原因在服务器端bind函数以及listen函数中已给出)
建立socket(与服务器一致 略)
发起连接:
参数释义:sockfd 系统返回的一个socket serv_addr 服务器监听的socket地址(即在服务器中自定义的socket地址 存放在sockaddr_in 结构体中) addr_len 地址长度
数据读写(与服务器一致 略)
关闭连接(与服务器一致 略)
基础完,参考资料linux高性能服务器编程。给出一个例子另外写出便于比对学习:https://mp.youkuaiyun.com/postedit/84073614