相关文章推荐
豪情万千的山羊  ·  Member 1 power ...·  12 小时前    · 
愉快的夕阳  ·  【bug解决】TypeError: ...·  3 月前    · 
风流倜傥的饭卡  ·  Visual Studio 2022 ...·  1 年前    · 

使用socketAPI前,要先将相关链接库(Ws2_32.lib)加入链接,并使用WSAStartUp函数初始化。

在linux中地址结构体sockaddr的结构与windows的不太一样,具体请百度

每个socket函数都可能失败(返回-1),需要判断结果

socket分成两种:

  • 一种专门用来监听新链接(或新活动),这种socket叫做 master socket ,一般只存在于服务器
  • 一种专门用来收发数据,这种socket叫做 connected socket ,客户端和服务器都存在
  • int socket(int af,int type,int protocol);

  • // 建立一个socket用于连接
  • af :address family,如AF_INET
  • type :连接类型,通常是SOCK_STREAM或SOCK_DGRAM
  • protocol :协议类型,通常是IPPROTO_TCP或IPPROTO_UDP
  • // 返回值 :socket的编号,为-1表示失败
  • int bind(int socket,sockaddr * address,uint addrlen);

  • // 将一个地址和一个端口号绑定到一个socket连接上
  • // socket :之前创建的socket
  • // sockaddr :一个用来存放Ip地址和端口号的结构体
  • // addrlen :上述结构体的长度
  • // 返回值:为-1表示失败,若端口被占用,会从新绑定一个 随机端口 (仍返回失败)
  • // 地址绑定为0表示绑定本机所有IP
  • int sendto(int socket,char * buf,uint buflen,int flag,sockaddr * address,uint addrlen); 【仅UDP】

  • // 向一个指定的地址发送缓冲区内指定长度的消息
  • // socket :之前创建的socket
  • // buf :要发送的缓冲区
  • // buflen :要发送的长度
  • // flag :一般为0
  • // sockaddr :目标地址
  • // addrlen :上述结构体的长度
  • // 返回值:发送出去的长度
  • int recvfrom(int socket,char * buf,uint buflen,int flag,sockaddr * fromaddr,int * addrlen); 【阻塞】【仅UDP】

  • // 接收消息,可以获取发送方的地址
  • // fromaddr :发送方地址(输出参数)
  • // addrlen :发送方地址结构体的长度(输入输出参数)
  • // 返回值:>0表示收到的字节数,=0表示连接被关闭,-1表示出错
  • int recv(int socket,char * buf,uint buflen,int flag); 【阻塞】

  • // UDP时:接收任何一个发送到该socket的消息(无法获取发送方地址)
  • // TCP时:接收一个已连接的socket (connected socket)发送的信息
  • // socket :UDP时,为之前创建的socket,TCP时,为connected socket
  • // buf :接收的缓冲区
  • // buflen :缓冲区的长度
  • // flag :一般为0
  • // 返回值:>0表示收到的字节数,=0表示连接被关闭,-1表示出错
  • // 注意:对于TCP,请确保socket是已连接的,因为只有已连接的socket会阻塞此函数
  • // 该函数实际上是从缓冲区取指定长度的数据,如果缓冲区没有数据,则会阻塞;如果没有取完,则下次使用此函数的时候不会阻塞
  • // 应注意:当一次无法获得对方发送的全部数据,在数据不完整的时候,程序可能无法向下执行,可以考虑将数据放在缓冲区中,等数据全部接收完成的时候再使用
  • int getsockname(int socket,sockaddr * address,int * addrlen);

  • // 获取指定socket上绑定的IP、端口信息(不能获取connected socket上的地址信息)
  • // address :socket上绑定的地址(输出参数)
  • // addrlen :socket上绑定的地址结构体的长度(输入输出参数)
  • int getpeername(int socket,,sockaddr * address,int * addrlen); 【仅TCP】

  • // 获取一个已连接的socket的地址、端口信息
  • // 参数含义同上

  • struct sockaddr_in

  • 一个用来指定IP地址和端口号的结构体(不太好用,建议将其封装)
  • family // 即address family,如AF_INET
  • port // 端口号(注意要按位倒序,使用htons函数)
  • sin_addr.S_un.S_addr // 一个为long类型的ip地址
  • int listen(int socket,int maxconn); 【仅TCP】【服务器】

  • // 将一个socket设置为监听状态,专门用来监听的socket叫做master socket
  • // maxconn :最大接收连接数
  • // 返回值:失败返回-1,成功返回0
  • int accept(int socket,sockaddr * fromaddr,int * addrlen); 【阻塞】【仅TCP】【服务器】

  • // 接收一个客户机的连接,返回一个socket,来自客户机的socket叫connected socket
  • // socket :用来监听的socket(master socket)
  • // fromaddr :客户机的地址信息
  • // addrlen :地址结构体的长度(输入输出参数)
  • // 返回值:返回一个新的socket,这个socket专门用来与此客户机通讯(connected socket)
  • int connect(int socket,sockaddr * addr,int addrlen); 【仅TCP】【客户端】

  • // 使用当前socket连接一个地址(与服务器建立正式连接),此函数会触发服务器端的accept、select函数
  • // 注意:服务端接收的socket值和客户端socket值不一样
  • // addr :一般是服务器地址
  • UDP通讯流程

    WSAStartup()
    socket()
    bind()
    sendto(connected socket)/recv()/recvfrom()

    TCP通讯流程(服务器):

    WSAStartup()
    socket()
    bind()
    listen()
    accept()
    send()/recv()

    TCP通讯流程(客户端):

    WSAStartup()
    socket()
    bind()
    connect()
    send()/recv()