📄 socket.cpp
字号:
// A note on how events are processed, which is probably the most
// difficult thing to get working right while keeping the same API
// and functionality for all platforms.
//
// When GSocket detects an event, it calls wx_socket_callback, which in
// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket
// object. OnRequest does some housekeeping, and if the event is to be
// propagated to the user, it creates a new wxSocketEvent object and
// posts it. The event is not processed immediately, but delayed with
// AddPendingEvent instead. This is necessary in order to decouple the
// event processing from wx_socket_callback; otherwise, subsequent IO
// calls made from the user event handler would fail, as gtk callbacks
// are not reentrant.
//
// Note that, unlike events, user callbacks (now deprecated) are _not_
// decoupled from wx_socket_callback and thus they suffer from a variety
// of problems. Avoid them where possible and use events instead.
extern "C"
void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket),
GSocketEvent notification,
char *cdata)
{
wxSocketBase *sckobj = (wxSocketBase *)cdata;
sckobj->OnRequest((wxSocketNotify) notification);
}
void wxSocketBase::OnRequest(wxSocketNotify notification)
{
// NOTE: We duplicate some of the code in _Wait, but this doesn't
// hurt. It has to be here because the (GSocket) event might arrive
// a bit delayed, and it has to be in _Wait as well because we don't
// know whether the Wait functions are being used.
switch(notification)
{
case wxSOCKET_CONNECTION:
m_establishing = false;
m_connected = true;
break;
// If we are in the middle of a R/W operation, do not
// propagate events to users. Also, filter 'late' events
// which are no longer valid.
case wxSOCKET_INPUT:
if (m_reading || !m_socket->Select(GSOCK_INPUT_FLAG))
return;
break;
case wxSOCKET_OUTPUT:
if (m_writing || !m_socket->Select(GSOCK_OUTPUT_FLAG))
return;
break;
case wxSOCKET_LOST:
m_connected = false;
m_establishing = false;
break;
default:
break;
}
// Schedule the event
wxSocketEventFlags flag = 0;
wxUnusedVar(flag);
switch (notification)
{
case GSOCK_INPUT: flag = GSOCK_INPUT_FLAG; break;
case GSOCK_OUTPUT: flag = GSOCK_OUTPUT_FLAG; break;
case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break;
case GSOCK_LOST: flag = GSOCK_LOST_FLAG; break;
default:
wxLogWarning(_("wxSocket: unknown event!."));
return;
}
if (((m_eventmask & flag) == flag) && m_notify)
{
if (m_handler)
{
wxSocketEvent event(m_id);
event.m_event = notification;
event.m_clientData = m_clientData;
event.SetEventObject(this);
m_handler->AddPendingEvent(event);
}
}
}
void wxSocketBase::Notify(bool notify)
{
m_notify = notify;
}
void wxSocketBase::SetNotify(wxSocketEventFlags flags)
{
m_eventmask = flags;
}
void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id)
{
m_handler = &handler;
m_id = id;
}
// --------------------------------------------------------------------------
// Pushback buffer
// --------------------------------------------------------------------------
void wxSocketBase::Pushback(const void *buffer, wxUint32 size)
{
if (!size) return;
if (m_unread == NULL)
m_unread = malloc(size);
else
{
void *tmp;
tmp = malloc(m_unrd_size + size);
memcpy((char *)tmp + size, m_unread, m_unrd_size);
free(m_unread);
m_unread = tmp;
}
m_unrd_size += size;
memcpy(m_unread, buffer, size);
}
wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek)
{
if (!m_unrd_size)
return 0;
if (size > (m_unrd_size-m_unrd_cur))
size = m_unrd_size-m_unrd_cur;
memcpy(buffer, (char *)m_unread + m_unrd_cur, size);
if (!peek)
{
m_unrd_cur += size;
if (m_unrd_size == m_unrd_cur)
{
free(m_unread);
m_unread = NULL;
m_unrd_size = 0;
m_unrd_cur = 0;
}
}
return size;
}
// ==========================================================================
// wxSocketServer
// ==========================================================================
// --------------------------------------------------------------------------
// Ctor
// --------------------------------------------------------------------------
wxSocketServer::wxSocketServer(wxSockAddress& addr_man,
wxSocketFlags flags)
: wxSocketBase(flags, wxSOCKET_SERVER)
{
wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") );
m_socket = GSocket_new();
if (!m_socket)
{
wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") );
return;
}
// Setup the socket as server
m_socket->SetLocal(addr_man.GetAddress());
if (GetFlags() & wxSOCKET_REUSEADDR) {
m_socket->SetReusable();
}
if (m_socket->SetServer() != GSOCK_NOERROR)
{
delete m_socket;
m_socket = NULL;
wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") );
return;
}
m_socket->SetTimeout(m_timeout * 1000);
m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
wx_socket_callback, (char *)this);
}
// --------------------------------------------------------------------------
// Accept
// --------------------------------------------------------------------------
bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
{
GSocket *child_socket;
if (!m_socket)
return false;
// If wait == false, then the call should be nonblocking.
// When we are finished, we put the socket to blocking mode
// again.
if (!wait)
m_socket->SetNonBlocking(1);
child_socket = m_socket->WaitConnection();
if (!wait)
m_socket->SetNonBlocking(0);
if (!child_socket)
return false;
sock.m_type = wxSOCKET_BASE;
sock.m_socket = child_socket;
sock.m_connected = true;
sock.m_socket->SetTimeout(sock.m_timeout * 1000);
sock.m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
wx_socket_callback, (char *)&sock);
return true;
}
wxSocketBase *wxSocketServer::Accept(bool wait)
{
wxSocketBase* sock = new wxSocketBase();
sock->SetFlags(m_flags);
if (!AcceptWith(*sock, wait))
{
sock->Destroy();
sock = NULL;
}
return sock;
}
bool wxSocketServer::WaitForAccept(long seconds, long milliseconds)
{
return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG);
}
bool wxSocketBase::GetOption(int level, int optname, void *optval, int *optlen)
{
wxASSERT_MSG( m_socket, _T("Socket not initialised") );
if (m_socket->GetSockOpt(level, optname, optval, optlen)
!= GSOCK_NOERROR)
{
return false;
}
return true;
}
bool wxSocketBase::SetOption(int level, int optname, const void *optval,
int optlen)
{
wxASSERT_MSG( m_socket, _T("Socket not initialised") );
if (m_socket->SetSockOpt(level, optname, optval, optlen)
!= GSOCK_NOERROR)
{
return false;
}
return true;
}
// ==========================================================================
// wxSocketClient
// ==========================================================================
// --------------------------------------------------------------------------
// Ctor and dtor
// --------------------------------------------------------------------------
wxSocketClient::wxSocketClient(wxSocketFlags flags)
: wxSocketBase(flags, wxSOCKET_CLIENT)
{
}
wxSocketClient::~wxSocketClient()
{
}
// --------------------------------------------------------------------------
// Connect
// --------------------------------------------------------------------------
bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait)
{
GSocketError err;
if (m_socket)
{
// Shutdown and destroy the socket
Close();
delete m_socket;
}
m_socket = GSocket_new();
m_connected = false;
m_establishing = false;
if (!m_socket)
return false;
m_socket->SetTimeout(m_timeout * 1000);
m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
wx_socket_callback, (char *)this);
// If wait == false, then the call should be nonblocking.
// When we are finished, we put the socket to blocking mode
// again.
if (!wait)
m_socket->SetNonBlocking(1);
m_socket->SetPeer(addr_man.GetAddress());
err = m_socket->Connect(GSOCK_STREAMED);
if (!wait)
m_socket->SetNonBlocking(0);
if (err != GSOCK_NOERROR)
{
if (err == GSOCK_WOULDBLOCK)
m_establishing = true;
return false;
}
m_connected = true;
return true;
}
bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)
{
if (m_connected) // Already connected
return true;
if (!m_establishing || !m_socket) // No connection in progress
return false;
return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG |
GSOCK_LOST_FLAG);
}
// ==========================================================================
// wxDatagramSocket
// ==========================================================================
/* NOTE: experimental stuff - might change */
wxDatagramSocket::wxDatagramSocket( wxSockAddress& addr,
wxSocketFlags flags )
: wxSocketBase( flags, wxSOCKET_DATAGRAM )
{
// Create the socket
m_socket = GSocket_new();
if(!m_socket)
{
wxASSERT_MSG( 0, _T("datagram socket not new'd") );
return;
}
// Setup the socket as non connection oriented
m_socket->SetLocal(addr.GetAddress());
if( m_socket->SetNonOriented() != GSOCK_NOERROR )
{
delete m_socket;
m_socket = NULL;
return;
}
// Initialize all stuff
m_connected = false;
m_establishing = false;
m_socket->SetTimeout( m_timeout );
m_socket->SetCallback( GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
wx_socket_callback, (char*)this );
}
wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,
void* buf,
wxUint32 nBytes )
{
Read(buf, nBytes);
GetPeer(addr);
return (*this);
}
wxDatagramSocket& wxDatagramSocket::SendTo( wxSockAddress& addr,
const void* buf,
wxUint32 nBytes )
{
wxASSERT_MSG( m_socket, _T("Socket not initialised") );
m_socket->SetPeer(addr.GetAddress());
Write(buf, nBytes);
return (*this);
}
// ==========================================================================
// wxSocketModule
// ==========================================================================
class wxSocketModule : public wxModule
{
public:
virtual bool OnInit()
{
// wxSocketBase will call GSocket_Init() itself when/if needed
return true;
}
virtual void OnExit()
{
if ( wxSocketBase::IsInitialized() )
wxSocketBase::Shutdown();
}
private:
DECLARE_DYNAMIC_CLASS(wxSocketModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
#endif
// wxUSE_SOCKETS
// vi:sts=4:sw=4:et
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -