网络编程-accept函数

13.2.5  accept函数

处于监听状态的服务器在获得客户机的连接请求后,会将其放置在等待队列中。当系统空闲时,将接受客户机的连接请求。接收客户机的连接请求使用accept函数,该函数的具体信息如表13.6所示。

表13.6   accept函数

头文件

函数形式

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

返回值

成功

失败

是否设置errno

返回新的套接字文件描述符

−1

说明:

accept函数用于面向连接类型的套接字类型(SOCK_STREAM和SOCK_SEQPACKET)。accept函数将从连接请求队列中获得连接信息,创建新的套接字,并返回该套接字的文件描述符。新创建的套接字用于服务器与客户机的通信,而原来的套接字仍然处于监听状态。

accept函数的sockfd参数为监听的套接字描述符。addr参数为指向结构体sockaddr的指针。参数addrlen为addr参数指向的内存空间的长度。

错误信息:

EAGAIN:套接字处于非阻塞状态,当前没有连接请求。

EBADF:非法的文件描述符。

ECONNABORTED:连接中断。

EINTR:系统调用被信号中断。

EINVAL:套接字没有处于监听状态,或非法的addrlen参数。

EMFILE:达到进程打开文件描述符限制。

ENFILE:达到打开文件数限制。

ENOTSOCK:文件描述符为文件的文件描述符。

EOPNOTSUPP:套接字类型不是SOCK_STREAM。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

accept()函数

  准备好了,系统调用 accept() 会有点古怪的地方的!你可以想象发生 这样的事情:有人从很远的地方通过一个你在侦听 (listen()) 的端口连接 (connect()) 到你的机器。它的连接将加入到等待接受 (accept()) 的队列 中。你调用 accept() 告诉它你有空闲的连接。它将返回一个新的套接字文 件描述符!这样你就有两个套接字了,原来的一个还在侦听你的那个端口, 新的在准备发送 (send()) 和接收 ( recv()) 数据。这就是这个过程!
函数是这样定义的: 
#include ;
int accept(int sockfd, void *addr, int *addrlen); 
sockfd 相当简单,是和 listen() 中一样的套接字描述符。addr 是个指 向局部的数据结构 sockaddr_in 的指针。这是要求接入的信息所要去的地 方(你可以测定那个地址在那个端口呼叫你)。在它的地址传递给 accept 之 前,addrlen 是个局部的整形变量,设置为 sizeof(struct sockaddr_in)。 accept 将不会将多余的字节给 addr。如果你放入的少些,那么它会通过改
变 addrlen 的值反映出来。 
同样,在错误时返回-1,并设置全局错误变量 errno。 
现在是你应该熟悉的代码片段。 
#include ;
#include ;
#include ;
#define MYPORT 3490 /*用户接入端口*/ 
#define BACKLOG 10 /* 多少等待连接控制*/ 
main() 
   { 
  int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */ 
  struct sockaddr_in my_addr; /* 地址信息 */ 
  struct sockaddr_in their_addr; /* connector's address information */ 
  int sin_size; 
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 错误检查*/ 
my_addr.sin_family = AF_INET; /* host byte order */ 
  my_addr.sin_port = htons(MYPORT); /* short, network byte order */ 
  my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */ 
  bzero(&(my_addr.sin_zero),; /* zero the rest of the struct */ 
/* don't forget your error checking for these calls: */ 
  bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); 
listen(sockfd, BACKLOG); 
sin_size = sizeof(struct sockaddr_in); 
  new_fd = accept(sockfd, &their_addr, &sin_size); 
   . 
   . 
   . 

注意,在系统调用 send() 和 recv() 中你应该使用新的套接字描述符 new_fd。如果你只想让一个连接进来,那么你可以使用 close() 去关闭原 来的文件描述符 sockfd 来避免同一个端口更多的连接。


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  既然客户端已经很虔诚了,很真诚了,处于倾听状态,那么该是去尝试接受客户端请求的时候了,别只顾着倾听,不去接纳别人。接纳客户端请求的函数是accept, 我们先来看看函数的原型:

[cpp] view plain copy
  1. WINSOCK_API_LINKAGE  
  2. SOCKET  
  3. WSAAPI  
  4. accept(  
  5.     SOCKET s,  
  6.     struct sockaddr FAR * addr,  
  7.     int FAR * addrlen  
  8.     );  

       函数的第一个参数用来标识服务端套接字(也就是listen函数中设置为监听状态的套接字),第二个参数是用来保存客户端套接字对应的“地方”(包括客户端IP和端口信息等), 第三个参数是“地方”的占地大小。返回值对应客户端套接字标识。

     实际上是这样的: accept函数指定服务端去接受客户端的连接,接收后,返回了客户端套接字的标识,且获得了客户端套接字的“地方”(包括客户端IP和端口信息等)。

     accept函数非常地痴情,痴心不改:如果没有客户端套接字去请求,它便会在那里一直痴痴地等下去,直到永远(注意, 此处讨论的是阻塞式的socket.  如果是非阻塞式的socket, 那么accept函数就没那么痴情了, 而是会立即返回, 并意犹未尽地对未来的客户端扔下一句话: 我等了你, 你不来, 那就算了, 我懒得鸟你)。

 

     可是,我不想等了,我要睡觉了。睡觉之前,最后来看看accpt函数的用法:

unsigned int sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len);




你可能感兴趣的:(网络编程-accept函数)