socket套接字如何建立连接?


差一点

我们就擦肩而过了

有趣

有用

有态度


导学问题:

1、套接字如何实现非阻塞调用?2、客户端能调用 bind 函数绑定端口吗?

服务端准备连接

  1. 创建一个套接字
int socket(int domain, int type, int protocol)
  • domain :
    • PF_INET:ipv4套接字
    • PF_INET6 :ipv6套接字
    • PF_LOCAL:本地套接字
    • ...
  • type:
    • SOCK_ATREAM:表示字节流,对应TCP
    • SOCK_DGRAM:表示数据包,对应UCP
    • SOCK_RAW:表示原始套接字
  • protocol:基本废弃,置0即可

如果执行成功,它会返回一个int类型的文件描述符

  1. 绑定套接字地址

    bind(int fd,sockaddr *addr,socklen_t len)

    注意:关于套接字地址的类型介绍,可以查看我前面的其他文章。虽然这里接收的是通用地址格式,但实际上传入的参数可能是 IPv4、IPv6 或者本地套接字格式。因此bind 函数会根据 len 字段判断传入的参数 addr 该怎么解析,len 字段表示的就是传入的地址长度,它是一个可变值。

    另外,网络环境中每台主机的ip地址都不相同,我们为了让程序运行在任意主机上,通常会在bind主机地址的时候,选择一个"通配地址"。对于 IPv4 的地址来说,使用 INADDR_ANY 来表示通配地址的设置,如下图:

    struct sockaddr_in text;text.sin_addr.s_addr = htonl (INADDR_ANY); /* IPV4 通配地址 */
    • fd:文件描述符
    • addr:套接字地址
    • len:套接字地址长度
  2. 监听套接字

    初始化创建的套接字,默认是一个"主动"套接字,我们可以使用它去链接其他的主机(通过connect函数,稍后会介绍i)。但是,我们可以通过listen函数,使它化主动为被动,静静地等待其他主机来连接它。

    int listen(int socket,int backlog)
    • socket:文件描述符
    • backlog:可以监听的连接数量
  3. 套接字连接成功

    当linux系统监听到客户端连接成功后,就需要把这个时间告诉给应用程序,好让应用程序开始进行收发工作。accept函数就是完成这个事情的。

    int accept(int listensockfd,struct sockaddr *cliaddr,socklen_t *addrlen)

    accept函数本身也会返回一个新的套接字描述符,为什么这里有两个套接字呢?

    主要原因是监听套接字必须要一直都存在,这样子我们才能够持续地监听客户端连接,而一旦新的客户端连接成功后,我们就要为它创建一个新的套接字,以后与该客户端的通信都将会通过这个套接字来实现

    • listensockfd:listen套接字,这是我们前面用socket函数创建的套接字
    • cliaddr:通过指针形式获取客户端地址
    • addrlen:获取地址的长度

客户端请求连接

前面讲述的bind、listen以及acept都是服务器端等待客户端连接的过程,下面我们来看客户端如何主动发起连接。

int connect(int fd,const struct sockaddr *servaddr,socklen_t addrlen)
  • fd:使用socket函数创建的套接字接口
  • servaddr:套接字地址结构指针,在该地址中必须包含服务器的ip以及端口号
  • addrlen:套接字地址长度

客户端在调用connect函数前不一定要调用bind函数,如果没有bind函数,linux系统会自动为我们寻找一个空闲端口来使用。


END


怎样学好网络编程?

分享一款Linux平台下的tcp协议栈!超级透彻!

TCP/IP和Unix的发展轨迹



扫码二维码

获取更多精彩

just enjoy it!