linux socket 异步,socket客户端多线程并发

今天给各位分享linux socket 异步的知识,其中也会对socket客户端多线程并发进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

linux非阻塞的socket发送数据出现EAGAIN错误的处理方法

非阻塞套接字在Linux中允许应用程序执行网络调用并立即返回,而无需等待结果。这在C/S(客户端/服务器)模式下尤其有用,因为它们通常采用异步非阻塞模式进行操作。

然而,当设置O_NONBLOCK属性后,如果发送缓存已满,send函数将返回EAGAIN或EWOULDBLOCK错误。这种情况下,通过封装socket_send函数,可以尽量将数据发送完毕再返回实际发送的字节数。在socket_send函数中,当写缓冲已满且返回EAGAIN错误时,会等待并再次尝试发送。

若在发送大包数据时,客户端未及时调用recv函数接收数据,服务器可能会陷入死循环,持续调用send函数直至返回EAGAIN错误。为解决此问题,可采用以下方法之一:

增大tcp_sendspace值,使其大于发送数据的size参数。

在调用send前,使用setsockopt函数将SNDBUF设置为更大的值。

使用write函数替代send,因为write没有设置O_NDELAY或O_NONBLOCK属性。

在发送数据前,增加EPOLLOUT事件监听,确保在数据全部发送完毕后取消此监听。使用socket缓存结构体组织数据,将待发送数据放入缓存,并在触发EPOLLOUT事件时调用socket_send函数发送数据,确保所有数据发送完毕后清除EPOLLOUT事件。

综上所述,合理管理发送缓存和事件监听,可以有效处理非阻塞socket发送数据时可能出现的EAGAIN错误。

linux socket和sock结构体的区别

//**************************************************************************

/* 1、每一个打开的文件、socket等等都用一个file数据结构代表,这样文件和socket就通过inode->u(union)中的各个成员来区别:

struct inode{

.....................

union{

struct ext2_inode_info ext2_i;

struct ext3_inode_info ext3_i;

struct socket socket_i;

.....................

} u;};

2、每个socket数据结构都有一个sock数据结构成员,sock是对socket的扩充,两者一一对应,socket->sk指向对应的sock,sock->socket

指向对应的socket;

3、socket和sock是同一事物的两个侧面,为什么不把两个数据结构合并成一个呢?这是因为socket是inode结构中的一部分,即把inode结

构内部的一个union用作socket结构。由于插口操作的特殊性,这个数据结构中需要有大量的结构成分,如果把这些成分全部放到socket

结构中,则inode结构中的这个union就会变得很大,从而inode结构也会变得很大,而对于其他文件系统这个union是不需要这么大的,

所以会造成巨大浪费,系统中使用inode结构的数量要远远超过使用socket的数量,故解决的办法就是把插口分成两部分,把与文件系

统关系密切的放在socket结构中,把与通信关系密切的放在另一个单独结构sock中;

*/

struct socket

{

socket_state state;//该state用来表明该socket的当前状态

typedef enum{

SS_FREE= 0,/* not allocated*/

SS_UNCONNECTED,/* unconnected to any socket*/

SS_CONNECTING,/* in process of connecting*/

SS_CONNECTED,/* connected to socket*/

SS_DISCONNECTING/* in process of disconnecting*/

} socket_state;

unsigned long flags;//该成员可能的值如下,该标志用来设置socket是否正在忙碌

#define SOCK_ASYNC_NOSPACE 0

#define SOCK_ASYNC_WAITDATA 1

#define SOCK_NOSPACE 2

struct proto_ops*ops;//依据协议邦定到该socket上的特定的协议族的操作函数指针,例如IPv4 TCP就是inet_stream_ops

struct inode*inode;//表明该socket所属的inode

struct fasync_struct*fasync_list;//异步唤醒队列

struct file*file;//file回指指针

struct sock*sk;//sock指针

wait_queue_head_t wait;//sock的等待队列,在TCP需要等待时就sleep在这个队列上

short type;//表示该socket在特定协议族下的类型例如SOCK_STREAM,

unsigned char passcred;//在TCP分析中无须考虑

};

如何控制C#Socket的连接超时时间

Socket.connect连接超时有二种情况: 1.由于网络的问题,TCP/IP三次握手时间>timeout的设置时间。这在国外访问weibo时,并且网络环境极差的情况下有可能发生。解决的办法:调大socket.connect方法中的timeout参数值,比如50s,linux默认最高是70s,如果超过70s没有意义,linux会采用70s.但是当调大之后,发现不到10s就报timeout exception。通过国外的机器ping api.weibo.com发现unreachable。说明客户端在传输层之下的网络层就发现连个Syn的报文都发不出去,更不用说三次握手了,客户端直接失败并抛timeout exception。经验:在connection timeout诊断的第一步应该是ping一下确认网络层没有问题。注:客户端设置了timeout,但并不会等到超时才返回异常。客户端只要第一时间发现连接失败,就会抛timeout exception。2.如果timeout设置的时间足够,但是由于服务器端的处理能力较差,比如缓冲连接队列较小,而应用层的处理能力没有连接缓冲快,导致缓冲连接占满,而拒绝新的连接。在服务端因为连接队列占满而拒绝服务的期间,客户端的通过TCP协议重试三次。每次的时间翻倍。如果三次时间的累加<timeout参数值且能连接上,属于正常情况,表示队列腾出空位放当前连接。如果三次时间的累加<timeout参数值且未能连接上,则客户端会立刻抛出timeout exception,而不等timeout到期才抛。下面是一个异步socket典型的连接程序connectDone是ManualResetEvent类型可以在connectDone.WaitOne();中使用等待的时间来限制连接超时比如connectDone.WaitOne(5000);是超时时间为5秒connectDone.WaitOne(); public void Conn(){try{ClientSocket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);IPAddress ipAddress= IPAddress.Parse(tcpIpServerIP);IPEndPoint remoteEP= new IPEndPoint(ipAddress, tcpIpServerPort);connectDone.Reset();ClientSocket.BeginConnect(remoteEP,new AsyncCallback(ConnectCallback),ClientSocket);connectDone.WaitOne();StateObject state= new StateObject(bufferSize,ClientSocket);ClientSocket.BeginReceive(state.buffer,0,bufferSize,0,new AsyncCallback(ReceiveCallback), state);}catch(Exception e){OnErrorEvent(new ErrorEventArgs(e));}}所有代码见:

阅读剩余
THE END