accept函数作用?
accept()
原型:intaccept(intsockfd,structsockaddr *addr, socklen_t *addrlen)
功能描述:accept()函数仅被TCP类型的服务器程序调用。
从已完成连接队列返回下一个建立成功的连接,如果已完成连接队列为空,线程进入阻塞态睡眠状态。成功时返回套接字描述符,错误时返回-1。
如果accpet()执行成功,返回由内核自动生成的一个全新socket描述符,用它引用与客户端的TCP连接。
通常我们把accept()第一个参数成为监听套接字(listening socket),把accept()功能返回值成为已连接套接字(connected socket)。
一个服务器通常只有1个监听套接字,监听客户端的连接请求;服务器内核为每一个客户端的TCP连接维护1个已连接套接字,用它实现数据双向通信。
参数解释:
sockfd–socket()函数返回的描述符;
addr– 输出一个的sockaddr_in变量地址,该变量用来存放发起连接请求的客户端的协议地址;
addrten– 作为输入时指明缓冲器的长度,作为输出时指明addr的实际长度。
延伸阅读
accept得到的socket是阻塞的还是非阻塞的?
阻塞模式和非阻塞模式的主要区别在于无请求来到时,阻塞模式会一直停在接收函数即accep函数,直到有请求到来才会继续向下进行处理。
而非阻塞模式下,运行接收函数,如果有请求,则会接收请求,如果无请求,会返回一个负值,并继续向下运行。一般来说,使用阻塞模式的程序比较多,因为阻塞模式是由内核保障等待请求的,当他阻塞时不占用系统资源,而非阻塞模式需要我们人工轮询,占用资源较多。另外,阻塞模式可以使用select函数设置超时时间,具体可以参考相关书籍。
半连接与全连接的区别?
半连接队列
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列(SYN队列),并向客户端响应 SYN+ACK。
全连接队列
服务端收到第三次握手的ACK后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到accept队列,等待进程调用accept 函数时把连接取出来。
关于winsock2中的connect函数?
1,只要client收到server的syn+ack,发送ack,client就认为三次握手建立完成,状态变为Established。阻塞的connect调用成功返回;对于非阻塞的connect调用,都会立马返回,使用select、poll或者epoll机制来判断socket是否可写来判定连接是否建立。
Established状态下的client自然是可以发送数据给server的。
2,如果client的最后一个ack,中途丢失或者被server主动忽略或丢弃,server在定时器溢出后,会重发syn+ack,client向server发送数据,server并不会返回Rst。
要模拟这种场景,有两种方式:1)收到server的syn+ack后,拔掉客户端的网线;2)让server端的accept队列塞满,主动丢弃ack。第一种场景模拟起来,难度比较大,于是我们采用第二种。
我采用go写的server来模拟。将net.core.somaxconn设置为2(因为go中listen调用,传入的即为系统的上限制),方便模拟。
客户端发送10个connect请求。
测试结果中,反映了下面几点:
1)客户端在发送完ack后(13:48:52.999239),立马(13:48:52.999879)开始发送数据;
2)发送的数据超时后,开始重试;
3)收到服务器重发的syn+ack后,客户端发送ack;
4)当服务器的syn+ack重试次数超过系统设置值后,断开连接,发送Rst包给客户端。
结论:客户端发送完最后一个ack后,就认为连接建立,connect成功!
3,accept成功?这个更简单了,accept函数调用只是去accept队列中取出一个连接而已,对服务器而言,只要接收了客户端的ack(注意,不忽略不抛弃哦),状态变更为Established了,而不是accept调用成功才变成Established的。
4,tcp的backlog队列
linux在实现tcp协议栈的时候,采用了两个队列,syn和accept队列。
当接收了对端的syn后,将其放入syn队列;当接收了对端的ack后,将syn队列中的连接转移到accept队列。
5,如果backlog队列满了,咋办?如果服务器端Established了,但突然客户端断网了,服务器进入半连接,咋办?如果客户端不停的发送syn包咋办?等等。。。很多问题。。这将会在我的
浅析TCP(上) – 曹东的文章 – 知乎专栏
中篇中详细介绍,敬请期待!
socket通信服务器端怎么写?
建立socket套接字,使用socket函数
绑定监听的端口与IP,使用bind函数
启动监控,使用listen函数
接受连接,使用accept函数
进入收发消息。
wxpython bind函数的作用?
1调用socket函数,建立一个套接字,该套接字用于接下来的网络通信
2调用bind函数,将该套接字绑定一个地址和端口号
3调用listen函数,使用该套接字监听连接请求
4调用accept函数,接受该套接字连接请求
linux accept()函数一直处于阻塞状态,什么原因?
accept()函数就是阻塞的啊,要等待接收到有客户端请求才可以进行后续的操作,你所谓的不可以是指什么?
accept函数的用法?
listen函数在一般在调用bind之后-调用accept之前调用,它的函数原型是:
intlisten(intsockfd,intbacklog)
参数sockfd
被listen函数作用的套接字,sockfd之前由socket函数返回。在被socket函数返回的套接字fd之时,它是一个主动连接的套接字,也就是此时系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接,然后在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接。由于系统默认时认为一个套接字是主动连接的,所以需要通过某种方式来告诉系统,用户进程通过系统调用listen来完成这件事。
参数backlog
这个参数涉及到一些网络的细节。进程处理一个一个连接请求的时候,可能还存在其它的连接请求。因为tcp连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。
毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。
accept函数
摘要:accept()用来接受参数s的socket连接,它的函数原型是:
intaccept(ints,structsockaddr*addr,int*addrlen)
服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回invalid_socket。该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。