网络编程之套接字
Posted hangzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程之套接字相关的知识,希望对你有一定的参考价值。
套接字
套接字格式
IPv4 IPv6 本地
套接字建立连接
TCP三次握手:使用套接字建立连接
过程
服务端准备连接
-
创建套接字
/** * domain:指定套接字格式:PF_INET、PF_INET6 以及 PF_LOCAL 等 * type:字节流TCP,数据报UDP,原始套接字 * protocol:0 */ int socket(int domain, int type, int protocol)
-
绑定地址
调用bind函数把套接字和套接字地址绑定,像登记电话号码一样
/** * fd:套接字 * addr:一般地址被转为通配地址 todo * len:地址长度 */ bind(int fd, sockaddr * addr, socklen_t len)
-
监听客户端连接
调用listen函数,告诉系统内核:这个套接字用来等待客户端请求;这样系统内核会为此做好准备,如完成连接队列。
/** * socketfd:套接字 * backlog:未完成连接队列大小,决定可接收的并发数目 */ int listen (int socketfd, int backlog)
-
接收客户端请求
客户端请求到达,服务端应答成功,连接建立(TCP三次握手),调用accept函数通知应用程序,让其感知到这个连接,并返回给一个客户端独有的已连接套接字,用于客户端和服务器之间的通信,当TCP连接断开,那么这个套接字就会被关闭。
如果使用的是阻塞式模型,accept会阻塞调用直到有一个连接过来。
/** * listensockfd:套接字(这是经历创建/监听得到的,公用的,它一直处于监听状态) * cliaddr:客户端地址 * addrlen:地址长度 * 返回套接字:已连接套接字描述字(这是单独给当前客户端创建的,后面都使用这个套接字和客户 * 端通信) */ int accept(int listensockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
客户端发起连接
-
建立套接字
-
向服务端发起请求
客户端调用connect函数和服务端建立连接,客户端无需调用bind函数来绑定端口,系统会自动随机分配一个空闲的临时端口,保证端口占用不会发生冲突。
/** * socketfd:连接套接字 * servaddr:服务端地址 */ int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
如果使用TCP套接字,那么这个connect过程将发生TCP三次握手,以下是阻塞式模型。TCP连接需要建立三次握手,是因为信道是不可靠的,所以需要保证连接双方各自收发消息的能力都正常,以可靠的传输信息。
套接字收发数据
一段数据流从应用程序发送端到接收端一个经历6次拷贝:用户空间(应用程序)——>发送缓冲区(系统内核)——>报文封装 * 2
发送数据
发送缓冲区:
内核缓冲区总是充满数据时会产生粘包的问题,而且w网络传输大小MTU也会限制每次发送的大小,缓冲区内的数据什么时候被发送由系统内核决定,所以缓冲区大小无限大并不会提高效率
(阻塞套接字)每次TCP连接成功建立后,内核系统会为每个连接建立发送缓冲区,如果x系统内核的发送缓冲区足够大,那么直接存储,如果不够大,应用程序会被阻塞,不返回,有点空间就先一点点的存储,等到全部存储到缓冲区中,函数才会被返回。
当TCP连接建立后,系统内核会将发送缓冲区中的数据,按照TCP/IP语义封装成TCP的MSS包,及IP的MTU包,最后走数据链路层发送出去。
/**
* 文件写函数:系统内核向文件系统中写入字节流,size与字节流大小必须一致
* 实现:把数据从应用程序中拷贝到操作系统内核的发送缓冲区中
* ssize_t:成功存储到发送缓冲区的大小,不代表对端成功接收到,发送是由系统内核决定的
*/
ssize_t write (int socketfd, const void *buffer, size_t size)
/**
* 可发送外带数据(基于TCP协议的紧急数据),用于客户端-服务端双向连接特定场景下的j紧急处理
*/
ssize_t send (int socketfd, const void *buffer, size_t size, int flags)
/**
* 指定多重缓冲区传输数据
*/
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
读取数据
因为在unix系统中,套接字描述本身和本地文件描述没有区别,所以都是用的处理本地文件的函数来读取数据
/**
* socketfd:套接字描述字
* buffer:读取缓冲区:存储读到的内容
* ssize_t:读取到的字节数:0表示EOF,读取结束
*/
ssize_t read (int socketfd, void *buffer, size_t size)
以上是关于网络编程之套接字的主要内容,如果未能解决你的问题,请参考以下文章