网络编程之套接字

匿名 (未验证) 提交于 2019-12-02 23:56:01

套接字

套接字格式

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)  

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!