当前位置: 技术问答>linux和unix
Linux 下非阻塞式Socket 连接问题
来源: 互联网 发布时间:2016-09-09
本文导语: 有一个客户端和服务端程序,服务端监听: 172.16.128.72:55771,accept成功一个后,不再accpet ,客户端用非阻塞式socket去 连接对端(先connect,成功情况下用select 再查询)。 问题是:启动多个客户端程序连接服务...
有一个客户端和服务端程序,服务端监听: 172.16.128.72:55771,accept成功一个后,不再accpet ,客户端用非阻塞式socket去 连接对端(先connect,成功情况下用select 再查询)。
问题是:启动多个客户端程序连接服务端,客户端均连接成功, 是什么原因呢?
通过netstat 查询如下:
服务端:
netstat -a |grep 55771
tcp 0 0 f1s9:55771 *:* LISTEN
tcp 0 0 f1s9:55771 f1s8:56699 SYN_RECV
tcp 0 0 f1s9:55771 f1s8:48426 SYN_RECV
tcp 0 0 f1s9:55771 f1s8:53168 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:58658 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:59174 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:47150 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:53550 ESTABLISHED
客户端:
netstat -a |grep 55771
tcp 0 0 f1s8:53550 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:56699 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:53168 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:59174 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:58658 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:47150 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:48426 f1s9:55771 ESTABLISHED
问题是:启动多个客户端程序连接服务端,客户端均连接成功, 是什么原因呢?
通过netstat 查询如下:
服务端:
netstat -a |grep 55771
tcp 0 0 f1s9:55771 *:* LISTEN
tcp 0 0 f1s9:55771 f1s8:56699 SYN_RECV
tcp 0 0 f1s9:55771 f1s8:48426 SYN_RECV
tcp 0 0 f1s9:55771 f1s8:53168 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:58658 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:59174 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:47150 ESTABLISHED
tcp 0 0 f1s9:55771 f1s8:53550 ESTABLISHED
客户端:
netstat -a |grep 55771
tcp 0 0 f1s8:53550 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:56699 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:53168 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:59174 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:58658 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:47150 f1s9:55771 ESTABLISHED
tcp 0 0 f1s8:48426 f1s9:55771 ESTABLISHED
|
因为accept发生在3次握手成功建立TCP连接之后,
而建立TCP连接后,connect就已经返回成功了,
accept只是从已连接的TCP队列中取一个绑到fd上返回,
不管有没有accept,都不影响3次握手(connect).
而建立TCP连接后,connect就已经返回成功了,
accept只是从已连接的TCP队列中取一个绑到fd上返回,
不管有没有accept,都不影响3次握手(connect).
|
TCP协议栈会自动建立好连接,服务端应用程序是否调用accept,对此事不影响,
打个比方,你有5个手机,有3个人同时给你给其中3个手机打电话,3个手机都响了,
你接(accept)了其中一个,另外两个没有接,但是另外两个打电话的人,能听见"嘟"声,
或者听见你的彩铃,他们知道电话打通了,只是没有人接。
线路通或不通,是运营商(协议栈)的事情,两人沟通却是自己(应用层)的事情,
这就需要用两人都懂的方式(上层协议, 如HTTP)交谈了,可以是普通话,也可以是英语。
|
对方没有accept,是客户端应用层收不到回复的充分不必要条件,
即使对方已经accept并且回复数据了,也有多个原因能造成客户端收不到回复,
所以光凭借这点是无法判断对方有没有accept的,客户端不应过分关心服务端的非业务逻辑部分。
如果应用层出现这种需求,可能需要再斟酌斟酌。一般不需要做这样的判断,只管计时和收发数据,
如果超时,就可以认为服务因为某些原因不可用了,例如浏览器打开一个页面时,有时会看到超时提示.
至于超时的原因,浏览器不会细说,也不会去尝试分析,只是做到提示“超时”这么个粒度。
|
ACCEPT(2) Linux Programmer's Manual ACCEPT(2)
NAME
accept - accept a connection on a socket
SYNOPSIS
#include /* See NOTES */
#include
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
DESCRIPTION
The accept() system call is used with connection-based socket types
(SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection
request on the queue of pending connections, creates a new connected
socket, and returns a new file descriptor referring to that socket.
The newly created socket is not in the listening state. The original
socket sockfd is unaffected by this call.
The argument sockfd is a socket that has been created with socket(2),
bound to a local address with bind(2), and is listening for connections
after a listen(2).
NAME
accept - accept a connection on a socket
SYNOPSIS
#include /* See NOTES */
#include
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
DESCRIPTION
The accept() system call is used with connection-based socket types
(SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection
request on the queue of pending connections, creates a new connected
socket, and returns a new file descriptor referring to that socket.
The newly created socket is not in the listening state. The original
socket sockfd is unaffected by this call.
The argument sockfd is a socket that has been created with socket(2),
bound to a local address with bind(2), and is listening for connections
after a listen(2).
|
你的netstat显示,已经accept了,tcp握手成功,至于你说没成功,我想你的判断失误了。
你如何判断没成功?你后面又说多个客户端成功,那说明服务端没问题。
但是你一会儿说成功,一会儿说不成功,把俺搞晕了。
你如何判断没成功?你后面又说多个客户端成功,那说明服务端没问题。
但是你一会儿说成功,一会儿说不成功,把俺搞晕了。
|
你一次accept都不运行试试,一样会连接成功,accept是从已连接队列里取出连接。
|
建议用google.com搜索以下关键字,找几篇相关王章看看
tcp backlog
tcp syncookie
tcp three-way handshake
|
正解