首页 > 编程知识 正文

socket函数用法,socket 方法

时间:2023-05-06 06:39:42 阅读:186146 作者:2967

常用socket函数详解

关于套接字函数,我知道各自的含义和基本功能,但每次使用都会去百度。 我也记得参数是什么,返回值表示什么意思,很少使用,不准确。 每次都查半天,经常在这里烦恼。 干脆简单易懂、透明地记录下来,自己就容易记住了。 另外,以后不要调查或回头看。

主要介绍: socket、bind、listen、connect、accept、send、sendto、recv、recvfrom、close、shutdown

网络中的进程通过套接字进行通信,但什么是套接字呢? socket源于Unix,而Unix/Linux的基本哲学之一是“所有文件”,可以在“打开-打开”-读写-关闭“关闭”模式下操作。 我的理解是,套接字是这种模式的实现,套接字是一种特殊的文件。

linux和windows环境的头文件主要是#includesys/socket.h和#includeWinSock2.h

本节详细介绍了如何使用每个函数以及如何确定和处理返回值。 另外,关于函数调用后内核的详细动作过程,可以参考UNIX网络编程第1卷或TCPIP详细调查第2卷。

1. socket

int http://www.Sina.com/(int domain,int type,int protocol ) )。

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _返回值:非负描述符成功,-1 -错误

其中:

family表示协议族/域,通常是AF_INET、AF_INET6、AF_LOCAL等;

type是套接字类型,主要是SOCK_STREAM、SOCK_DGRAM、SOCK_RAW;

协议通常为0。 如果成功,则会返回非负的小整数值,就像文件描述符一样。

在windows环境中,必须先调用WSAStartup函数完成Winsock服务的初始化,然后才能调用该函数,如下所示

#includeWinSock2.h

WSADATA wdata;

生成开始(make word (2,2 ),wdata )!=0}{

return INVALID_SOCKET;

() ) ) ) )。

可以稍后调用套接字函数,参数的含义与linux环境一致。

socket

int http://www.Sina.com/(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen ) ) )。

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _返回值: 0成功,-1 -错误

套接字函数返回描述符时,它只是存在于该协议族的空间中,没有分配具体的协议地址(在此为IPv4/IPv6和端口号的组合)。 bind函数可以将一组固定地址绑定到套接字FD。

其中:

sockfd是socket函数返回的描述符;

myaddr指定要绑定的IP和端口号,并使用网络端序或大端模式;

addrlen是上一个struct sockaddr (等于sockaddr _ in )的长度。

为了统一地址结构的表示方法,将统一接口函数以便不同的地址结构将由诸如bind (,connect )、recvfrom )、sendto )之类的函数来调用。 但是,在一般的编程中不直接操作该数据结构,而是使用与其等价的其他数据结构sockaddr_in。

服务器通常在启动时使用众所周知的协议地址提供服务,客户可以通过该地址连接服务器,客户端可以指定也可以不指定IP或端口。 如果未分配,系统会自动分配。 因此,服务器端通常在listen之前调用bind (),但客户端不调用,而是connect ) )时由系统随机生成一个。

Windows上的版本:

intbind(insockets,IN const struct sockaddr FAR * name,IN int namelen );

2. bind

int http://www.Sina.com/(int sockfd,int backlog ) )。

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _返回值: 0成功,-1 -错误

                                                                                                                                                                                                       (截图来自:《UNIX网络编程第一卷》)

两个队列之和数量不得超过backlog.

 

 

4.  connect

intconnect(int sockfd,conststruct sockaddr *addr, socklen_t addrlen)

______________________返回值:0 – 成功,-1 - 出错

       通过此函数建立于TCP服务器的连接,实际是发起三次握手过程,仅在连接成功或失败后返回。参数sockfd是本地描述符,addr为服务器地址,addrlen是socket地址长度。

UDP的connect函数,结果与tcp调用不相同,没有三次握手过程。内核只是记录对方的ip和端口号,他们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。

 

 

5.  accept

intaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

______________________返回值:非负描述符 – 成功,-1 - 出错

                                                                                                                                                                           (截图来自:《UNIX网络编程第一卷》)

 

 

6.  send

ssize_tsend(int sockfd,constvoid *buf, size_t len,int flags)

返回值:

>0 – 成功拷贝至发送缓冲区的字节数(可能小于len),

-1 – 出错,并置错误号errno.

Windows版本:

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

       失败时返回 -1/SOCKET_ERROR

其中:

       sockfd:发送端套接字描述符(非监听描述符)

       buf:应用要发送数据的缓存

       len:实际要发送的数据长度

       flag:一般设置为0

每个TCP套接口都有一个发送缓冲区,它的大小可以用SO_SNDBUF这个选项来改变。调用send函数的过程,实际是内核将用户数据拷贝至TCP套接口的发送缓冲区的过程:若len大于发送缓冲区大小,则返回-1;否则,查看缓冲区剩余空间是否容纳得下要发送的len长度,若不够,则拷贝一部分,并返回拷贝长度(指的是非阻塞send,若为阻塞send,则一定等待所有数据拷贝至缓冲区才返回,因此阻塞send返回值必定与len相等);若缓冲区满,则等待发送,有剩余空间后拷贝至缓冲区;若在拷贝过程出现错误,则返回-1。关于错误的原因,查看errno的值。

       如果send在等待协议发送数据时出现网络断开的情况,则会返回-1。注意:send成功返回并不代表对方已接收到数据,如果后续的协议传输过程中出现网络错误,下一个send便会返回-1发送错误。TCP给对方的数据必须在对方给予确认时,方可删除发送缓冲区的数据。否则,会一直缓存在缓冲区直至发送成功(TCP可靠数据传输决定的)。

 

 

7.  sendto

ssize_t sendto(int sockfd,const void *buf, size_t len, int flags,

                      const struct sockaddr *dst_addr, socklen_t addrlen);

       windows版本:

int sendto(IN SOCKET s, IN const char FAR * buf, IN int len, IN int flags, IN const struct sockaddr FAR * to, IN int tolen)

 

通常用于UDP套接口,用数据报方式进行数据传输。由于无连接的数据报模式下,没有建立连接,需指明目的地址,addrlen通常为sizeof(sockaddr)的长度。成功时返回发送的字节数,失败返回-1。

       当本地与不同目的地址通信时,只需指定目的地址,可使用同一个UDP套接口描述符sockfd,而TCP要预先建立连接,每个连接都会产生不同的套接口描述符,体现在:客户端要使用不同的fd进行connect,服务端每次accept产生不同的fd。

       因为UDP没有真正的发送缓冲区,因为是不可靠连接,不必保存应用进程的数据拷贝,应用进程中的数据在沿协议栈向下传递时,以某种形式拷贝到内核缓冲区,当数据链路层把数据传出后就把内核缓冲区中数据拷贝删除。因此它不需要一个发送缓冲区。写UDP套接口的sendto/write返回表示应用程序的数据或数据分片已经进入链路层的输出队列,如果输出队列没有足够的空间存放数据,将返回错误ENOBUFS.

 

关于TCP/UDP套接口的发送缓冲区理解:

(1)下图展示了应用进程写数据到TCP套接口的过程:

每一个TCP套接口有一个发送缓冲区,我们可以用SO_SNDBUF套接口选项来改变这个缓冲区的大小。当应用程序调用write时,内核从应用程序进程的缓冲区中拷贝所有数据到套接口的发送缓冲区。如果套接口的发送缓冲区容不下应用程序的所有数据(或是应用程序的缓冲区大于套接口发送缓冲区,或是套接口发送缓冲区还有其他数据),应用进程将被挂起(睡眠)。这里假设套接口是阻塞的,它是通常的缺省设置(还有非阻塞的套接口)。内核将不从write系统调用返回,直到应用程序缓冲区中的所有数据都拷贝到套接口发送缓冲区。因此从写一个TCP套接口的write调用成功返回仅仅表示我们可以重新使用应用进程的缓冲区。它并不告诉我们对端的TCP或应用程序已接收到数据。

TCP取套接口发送缓冲区的数据并把它发送给对端TCP,其过程基于TCP数据传送的所有规则。对端TCP必需确认收到数据,只有收到对端的ACK,本端TCP才能删除套接口发送缓冲区中已确认的数据。TCP必需保留数据拷贝直到对端确认为止。

TCP以MSS大小的或更小的块把数据传递给IP,同时给每个数据块安上一个TCP头部以构成TCP分节,其中的MSS是由对端通告的,当对端未通告时就用536这个值(IPv4的最小重组缓冲区字节数576减去IPv4头部字节20和TCP头部字节数20)。IP给每个TCP分节安上IP头部以构成IP数据报,查找其宿IP地址的路由表项以确定外出接口,然后把数据报传递给相应的数据链路。IP可能在把数据报传递给数据链路之前将其分片,不过我们已经谈到MSS选项的目的之一就是试图避免分片,而较新的实现又使用了路径MTU发现功能。每个数据链路都有一个输出队列,如果该队列已满,那么新到的分组将被丢弃,并沿协议栈向上返回一个错误,从链路层到IP层,再从IP层到TCP层。TCP将注意到这个错误,并在以后某个时刻重传相应分片。应用进程并不知道这种暂时情况。

      

(2)下图展示了应用进程写数据到UDP套接口的过程:

这一次我们展示的套接口发送缓冲区用虚线框,因为它并不存在。UDP套接口有发送缓冲区大小(我们可以用SO_SNDBUF套接口选项修改),不过它仅仅是写到套接口的UDP数据报的大小上限。如果应用进程写一个大于套接口发送缓冲区大小的数据包,内核将返回一个EMSGSIZE错误。既然UDP是不可靠的,它不必保存应用程序的数据拷贝,因此无需一个真正的发送缓冲区。(应用进程的数据在沿协议向下传递时,以某种形式拷贝到内核的缓冲区,然而数据链路层在送出这些数据后将丢弃该拷贝)

UDP简单地给用户数据报安上它的8个字节的头部以构成UDP数据报,然后传递给IP。IPv4或IPv6给UDP数据报安上相应的IP头部以构成IP数据报,执行路由操作确定外出接口,然后直接把数据包加入数据链路层输出队列(如果适合于MTU),或者分片后再把每个片加入数据链路层的输出队列。如果某个UDP应用进程发送大数据报,那么它比TCP应用进程更有可能分片,因为TCP会把应用数据划分成MSS大小的块,而UDP却没有对等的手段。

从写UDP套接口的write调用成功地返回表示用户写入的数据报或其所有片段已被加入数据链路层的输出队列。如果该队列没有足够的空间存放该数据报或它的某个片段,内核通常将给应用程序返回一个ENOBUFS错误。

 

8.  recv

ssize_t recv(int sockfd,void *buf, size_t len,int flags)

其中:

sockfd:接收端套接字描述符;

buf:指定缓冲区地址,用于存储接收数据;

len:指定的用于接收数据的缓冲区长度;

flags:一般指定为0

表示从接收缓冲区拷贝数据。成功时,返回拷贝的字节数,失败返回-1。阻塞模式下,recv/recvfrom将会阻塞到缓冲区里至少有一个字节(TCP)/至少有一个完整的UDP数据报才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1,置错误码为EWOULDBLOCK。

 

9.  recvfrom

ssize_t recvfrom(int sockfd,void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen)

windows版本:

int recvfrom(IN SOCKET s, OUT char FAR * buf, IN int len, IN int flags, OUT struct sockaddr FAR * from,IN OUT int FAR * fromlen)

着重强调参数:

       sockfd:接收端套接字描述

       buf:用于接收数据的应用缓冲区地址

       len:指名缓冲区大小

       flags:通常为0

       src_addr:数据来源端的地址

       addrlen:src_addr地址的长度

注意后两个参数是输出参数,其中addrlen既是输入又是输出参数,即值-结果参数,需要在调用时,指明src_addr的长度。另外,如果不关心数据发送端的地址,可以将后两者均设置为NULL。

 

10. close

close缺省功能是将套接字作“已关闭”标记,并立即返回到调用进程,该套接字描述符不能再为该进程所用:即不能作为read和write(send和recv)的参数,但是TCP将试着发送发送缓冲区内已排队待发的数据,然后按正常的TCP连接终止序列进行操作(断开连接4次握手-以FIN为首的4个TCP分节)。

 

11. shutdown

shutdown不仅可以灵活控制关闭连接的读、写或读写功能,而且会立即执行相应的断开动作(发送终止连接的FIN分节等),此时不论有多少进程共享此套接字描述符,都将不能再进行收发数据。

 

 

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。