wxSocket 实现分析和使用总结

本文详细分析了wxWidgets在Linux下wxSocket的实现,包括主要操作接口、wxSocketFlags及其影响,以及wxSocketBase::Read/Write的行为。讨论了在使用wxBufferedInputStream时的注意事项,强调了wxSOCKET_WAITALL与wxSocketBase::LastCount的使用限制,并给出了安全读写socket的建议。
摘要由CSDN通过智能技术生成

本编文章分析了wxSocket在Linux操作系统中的实现,并总结了相关使用方法。

wxSocket 属于wxWidgets的wxNet子module。wxSocket是对系统socket API的简单封装,对外提供了wxEvent通知机制,屏蔽了操作系统相关的实现细节。用户可以通过wxSocketClient/wxSocketServer来很方便的使用。

Note: 此处使用的wxWidgets 库的版本是 v2.8.9,主要涉及到代码文件 src/common/sckstrm.cpp, src/common/socket.cpp 和 src/unix/gsocket.cpp。

1. wxSocket 实现

wxSocket相关类UML图:

Inheritancegraph

在wx的在线manual里,可以看到wxNet相关的所有类。

1.1 主要操作接口

wxSocket主要的操作如下:

  1. basic IO
 
 
 
  1. - Close
  2. - Discard
  3. - Peek
  4. - Unread
  5. - Read
  6. - ReadMsg
  7. - Write
  8. - WriteMsg
  1. Socket state
 
 
 
  1. 2. Functions to retrieve current state and miscellaneous info.
  2. - Error
  3. - GetLocal/GetPeer
  4. - IsData
  5. - IsDisconnected/IsConnected
  6. - LastCount
  7. - LastError
  8. - IsOk
  9. - SaveState/RestoreState
  10. 2. Functions that perform a timed wait on a certain IO condition.
  11. - InterruptWait
  12. - Wait
  13. - WaitForLost
  14. - WaitForRead/WaitForWrite
  15. - and also:
  16. - wxSocketServer::WaitForAccept
  17. - wxSocketClient::WaitOnConnect
  18. 2. Functions that allow applications to customize socket IO as needed.
  19. - GetFlags/SetFlags
  20. - SetTimeout
  21. - SetLocal
  1. Handling socket events
 
 
 
  1. - Notify/SetNotify
  2. - GetClientData/SetClientData
  3. - SetEventHandler

用户可以方便的通过SetNotify来订阅想要通知的事件。基于此,可以完全把Read/Write操作事件化。

1.2 wxSocketFlags

wxSocketFlags用来控制socket的运行模式,主要的flag如下:

 
wxSocketFlags 含义
wxSOCKET_BLOCK Block the GUI (do not yield) while reading/writing data. 
wxSOCKET_NOWAIT  Read/write as much data as possible and return immediately. 
wxSOCKET_WAITALL  Wait for all required data to be read/written unless an error occurs.

a. wxSOCKET_BLOCK表示在调用wxSocketBase::Read/Write的时候,不会触发yield的操作。如果wxSocket本身在main thread里面进行读写操作,程序此时会不响应UI消息。而且由于yield操作本身可能会导致socket相关的操作重入(reentrant),这很可能不是用户代码想要的。所以一般推荐在wxSocket_BLOCK+thread环境下使用wxSocket,这样socket的读写操作就不会阻塞UI thread。

b. wxSOCKET_WAITALL与wxSOCKET_NOWAIT正好相反,分别用于同步和异步读写。

1.3 wxSocket实现

wxSocket 对 系统socket函数进行封装,内部的socket fd采用非阻塞模式。

src/unix/gsocket.cpp

  
  
  
  1. m_fd = socket(m_peer->m_realfamily,m_stream?SOCK_STREAM:SOCK_DGRAM,0);
  2. if(m_fd == INVALID_SOCKET)
  3. {
  4. m_error = GSOCKIOERR;
  5. return GSOCK_IOERR;
  6. }
  7. #ifdef SO_NOSIGPIPE
  8. setsockopt(m_fd,SOL_SOCKET,SO_NOSIGPIPE,(const char*)&arg,sizeof(arg));
  9. #endif
  10. #if defined(__EMX__)||defined(__VISAGECPP__)
  11. ioctl(m_fd,FIONBIO,(char*)&arg,sizeof(arg));
  12. #else
  13. ioctl(m_fd,FIONBIO,&arg);
  14. #endif

这里arg的值为1,通过ioctl来设置socket fd为非阻塞。

2. wxSocketBase::Read/Write

wxSocket本质上是non-blocking socket。我们可以通过wxSocketBase::Read/Write直接读写数据。同时wxNet也提供了wxSocket stream (wxSocketInputStream, wxSocketOuputStream)来读写数据。

通过wxSocket stream来读写数据和直接通过wxSocket来读写基本一样。但是wxSocket stream 的作用在于,我们可以利用wx库提供的通用的stream操作类来处理socket相关的读写。比如: 利用wxBufferedInputStream 和 wxBufferedOutputStream来进行带缓冲区的读写。

2.1 未设置wxSOCKET_WAITALL flag时的wxSocketBase::Read

问题: 假如直接调用wxSocketBase::Read或者wxSocketInputStream::Read读取一大块数据(e.g. 10MB),可能会发生什么情况?

答案: wxSocketInputStream::Read返回后,实际读取的字节数很随机,跟当前的系统状态有很大关系。

当然这样的行为和直接用系统函数recv(2)或read(2)从non-blocking socket 读取数据类似。

 这个通过查看wxSocketBase::_Read的实现(src/common/socket.cpp),很容易弄清楚。

  
  
  
  1.  wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes)
  2. {
  3. // ...
  4. int ret;
  5. if (m_flags & wxSOCKET_NOWAIT)
  6. {
  7. m_socket->SetNonBlocking(1);
  8. ret = m_socket->Read((char *)buffer, nbytes);
  9. m_socket->SetNonBlocking(0);
  10. if (ret > 0)
  11. total += ret;
  12. }
  13. else
  14. {
  15. bool more = true;
  16. while (more)
  17. {
  18. if ( !(m_flags
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值