socket函数

socket()

函数原型:

    int socket(int af, int type, int protocol);

参数说明:

  1. l  af    :指定一个协议簇(协议域),
     AF_INET – Ipv4协议
     AF_INET6 – Ipv6协议
     AF_LOCAL – UNIX协议域
  2. l  type :指定socket类型,常见的类型有:TCP(SOCK_STREAM)、UDP(SOCK_DGRAM)、SOCK_SEQPACKET、SOCK_RAW等,分别代表字节流、数据报、有序分组、原始套接口。
  3. l  protocol :指定相应的输出协议,也就是诸如TCP或UDP协议等。 设置为 0 时表示使用默认协议。常用的协议有 IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,他们分别对应TCP传输协议,UDP传输协议、STCP传输协议、TIPC传输协议。

 

SOCK_STREAM类型:

  • 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传输机制,为Internet地址族使用TCP。
  • 该种类型的套接口为全双向的字节流,对于流类套接口,在接收或发送数前必须处于已连接的状态。
  • 用connect()调用建立与另一套接口的连接,连接成功后,即可使用send()和recv()传输数据,当会话结束后,调用colsesocket()带外数据根据规定用send()和recv()来接收。
  • 实现SOCK_STREM类型套接口的通信协议保证数据不会丢失也不会重复,如果终端协议有缓冲区空间,且数据不能在一定时间发送成功,则认为连接中断,则后续的调用也将以WSAETIMOUT错误返回。

 

SOCK_DGRAM类型:

  • l  支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务,为Internet地址族使用UDP。
  • l  SOCK_DGRAM类型套接字口运行使用sendto()和recvfrom()从任意端口发送或接收数据包。这样一个套接口用connect()与一个指定端口连接,则可用send()和recv()与该端口进行数据包的发送和接收

 

 

send(),recv()   一般用于TCP

sendto(),recvfrom()    一般用于UDP

但是TCP也可以用sendto(),recvfrom(),反之UDP也可以用send(),recv()

 

send()

函数原型:

int send(SOCKET s, const char FAR *buf, int len, int flags);

参数说明:

  •        s      :指定的接收端套接字描述符
  •        buf  :存放应用程序要发送数据的缓冲区
  •        len  :实际要发送数据的字节数
  •        flags       :一般置0

同步Socket的send函数执行流程:

  1. 当调用该函数时,sen先比较待发送数据的长度len和套接字s的发送缓冲的长度,
    如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;
    如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据:
        如果是就等待协议把数据发送完成;
        如果协议还没开始发送s的缓冲区的数据或者s的发送缓冲区中没有数据,那么send就比较s的发送缓冲区的剩余空间和len:
            如果len大于剩余空间,send就一直等待协议把s的发送缓冲中的数据发送完;
            如果len小于剩余空间大小,send就仅仅把buf中的数据copy到剩余空间。(send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里,协议完成传输)。
  2. 如果send函数copy数据成功,就返回实际copy的字节数,
    如果send在copy数据时出错,那么send就返回SOCKET_ERROR;
    如果send在等待协议传送数据时网络断开的话,sned函数也返回SOCKET_ERROR

 

注意:

  1. sned函数把buf中的数据成功copy到s的发送缓冲区的剩余空间后他就返回了,但此时这些数据并不一定马上被传到连接的另一端,如果协议在后续的传输过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR
  2. 每一个除send外的Socket函数在执行的最开始最要先等待套接字的发送缓冲区中的数据被协议传送完毕后才能继续,如果在等待时出现网络错误,那么该Socket函数就要返回SOCKET_ERROR;在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会收到一个SIGPIPE信号,进程对信号的默认处理时进程终止(针对unix/linux内核的系统,编程者处理好此种情况,不然程序会意外终止)。

 

recv()

函数原型:

    int recv(SOCKET s, char FAR *buf, int len, in flags);

 

功能:

       从TCP连接的另一端接收数据,客户端、服务端应用程序都用recv函数接收数据。

参数说明:

       s      :指定接收端套接字描述符

       buf  :存放recv函数接收数据的缓冲区

       len  :缓冲区长度

       flags       :一般置0

 

Socket的recv函数执行流程:

  1. 当调用recv函数时,recv先等待s的发送缓冲区数据被协议传送完毕。
    如果协议在传送s的发送缓冲区中数据时出现网络错误,那么函数返回SOCKET_ERROR错误;
    如果s的发送缓冲区中没有数据或者数据被协议成功发送后完毕后,recv先检查套接字s的接收缓冲区;
    如果s的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,知道协议把数据接收完毕
  2. 当协议把数据接收完毕以后,recv函数酒吧接收缓冲区中的数据copy到buf中。(协议接收到的数据可能大于buf的长度,这时就要调用几次recv函数才能把s的接收缓冲区的数据copy完。recv函数仅是copy除数据,真正的接收数据是协议完成)。
  3. recv函数返回其实际copy的字节数
    如果recv在copy时出错,那么它返回SOCKET_ERROR
    热锅recv函数在等待协议接收数据时网络中断,那么它返回0。

 

注意:在unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv进程会收到一个SIGPIPE信号,进程默认执行终止。

 

sendto()在无连接的数据包socket方式下,由于本地socket没有与远端机器建立连接,所以在发送数据时应该指明目的地址。

函数原型:

       int sendto(int sockfd,   cosnt void *msg;   int len;    unsigned int flags; const struct sockaddr *to; int tolen);

 

参数说明:

       to    :表示目的主机ip和端口号信息;

       tolen:常常被赋值为sizeof(struct sockaddr)

返回值:

       发送成功返回发送的字节长度,发送失败返回-1.

 

recvfrom()

 

函数原型:

       int recvfrom(int sockfd, void *buf,      int len;    unsigned int flags; struct sockaddr *from,       int *fromlen);

参数说明:

       from       :是一个struct sockaddr类型的变量,该变量保存源机的IP地址和端口号。

       fromlen  :常常被赋值为sizeof(struct sockaddr)

返回值:

       fromlen包含实际存入from中的数据字节数。recvfrom()函数返回接收到的字节数,出现错误时返回-1。并置相应的errrno。

 

说明:

sendto()和recvfrom一般用于UDP协议中,但是如果TCP中connect函数调用后,他们也可以用于TCP传输。

对于数据包socket调用connect()函数时,也可以使用send()和recv()进行数据传输,但该socket仍然是socket,并且利用传输层的UDP服务,但是在发送和接收数据时,内核会自动添加目的和与源地址信息。

 

posted @ 2019-10-12 14:08  王清河  阅读(740)  评论(0编辑  收藏  举报