📄 tcpsocket.cpp
字号:
/****************************************************************************
*
* Multiplatform High-Performance Async Network Library
* Implementation of TCP Socket
* Copyright (c) 2007 Burlex
*
* This file may be distributed under the terms of the Q Public License
* as defined by Trolltech ASA of Norway and appearing in the file
* COPYING included in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include "Network.h"
TcpSocket::TcpSocket(int fd, size_t readbuffersize, size_t writebuffersize, bool use_circular_buffer, const sockaddr_in * peer)
{
SetFd(fd);
if(use_circular_buffer)
{
// m_writeBuffer = new CircularBuffer;
// m_readBuffer = new CircularBuffer;
m_writeBuffer = new StraightBuffer;
m_readBuffer = new StraightBuffer;
}
else
{
m_writeBuffer = new StraightBuffer;
m_readBuffer = new StraightBuffer;
}
m_writeBuffer->Allocate(writebuffersize);
m_readBuffer->Allocate(readbuffersize);
memcpy(&m_peer, peer, sizeof(sockaddr));
/* switch the socket to nonblocking mode */
u_long arg = 1;
ioctlsocket(fd, FIONBIO, &arg);
m_writeLock = 0;
m_deleted = false;
m_connected = true;
/* disable nagle buffering by default */
int arg2 = 1;
setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&arg2, sizeof(int));
}
TcpSocket::~TcpSocket()
{
delete m_writeBuffer;
delete m_readBuffer;
}
void TcpSocket::OnRead(size_t len)
{
/* This is called when the socket engine gets an event on the socket */
#ifdef NETLIB_IOCP
if(!len)
{
/* socket disconnected */
Disconnect();
return;
}
/* IOCP is easy. */
if(len != 0xFFFFFFFF)
m_readBuffer->IncrementWritten(len);
/* Wewt, we read again! */
OnRecvData();
if(!IsConnected())
return;
/* Setup another read event */
WSABUF buf;
buf.buf = (char*)m_readBuffer->GetBuffer();
buf.len = m_readBuffer->GetSpace();
DWORD recved;
DWORD flags = 0;
Overlapped * ov = new Overlapped;
memset(ov, 0, sizeof(Overlapped));
ov->m_op = IO_EVENT_READ;
if(WSARecv(m_fd, &buf, 1, &recved, &flags, &ov->m_ov, 0) == SOCKET_ERROR)
{
if(WSAGetLastError() != WSA_IO_PENDING)
Disconnect();
}
#else
/* Any other platform, we have to call recv() to actually get the data. */
int bytes = recv(m_fd, (char*)m_readBuffer->GetBuffer(), m_readBuffer->GetSpace(), 0);
/* Under some socket engines, if this returns 0, we're in deep poo poo. */
/* Check if recv() failed. */
if(bytes <= 0)
Disconnect(); // whoopes. :P
else
{
m_readBuffer->IncrementWritten(bytes);
OnRecvData();
}
#endif
}
void TcpSocket::OnWrite(size_t len)
{
/* Lock the buffer so nothing can modify it */
LockWriteBuffer();
/* This is called when the socket engine gets an event on the socket */
#ifdef NETLIB_IOCP
/* Data has already been output to the socket, we can clear the buffer */
if(!len)
{
Disconnect();
return;
}
m_writeBuffer->Remove(len);
/* Do we still have data to write? */
if(m_writeBuffer->GetSize())
sSocketEngine.WantWrite(this);
else
InterlockedDecrement(&m_writeLock);
#else
/* Push as much data out as we can in a nonblocking fashion. */
int bytes = send(m_fd, (const char*)m_writeBuffer->GetBufferOffset(), m_writeBuffer->GetSize(), 0);
if(bytes < 0)
Disconnect();
else
m_writeBuffer->Remove(bytes);
#endif
/* Unlock the write buffer, we're finished */
UnlockWriteBuffer();
}
void TcpSocket::Finalize()
{
sSocketEngine.AddSocket(this);
OnConnect();
}
bool TcpSocket::Write(const void * data, size_t bytes)
{
if(!m_connected)
return false;
bool rv = m_writeBuffer->Write(data, bytes);
if(rv)
{
#ifdef NETLIB_IOCP
/* On windows since you have multiple threads this has to be guarded. */
if(InterlockedCompareExchange(&m_writeLock, 1, 0) == 0)
sSocketEngine.WantWrite(this);
#else
if(!m_writeLock)
{
++m_writeLock;
sSocketEngine.WantWrite(this);
}
#endif
}
return rv;
}
void TcpSocket::Disconnect()
{
if(!m_connected) return;
m_connected = false;
OnDisconnect();
sSocketEngine.RemoveSocket(this);
shutdown(m_fd, SD_BOTH);
closesocket(m_fd);
if(!m_deleted)
Delete();
}
void TcpSocket::Delete()
{
if(m_deleted) return;
m_deleted = true;
sSocketDeleter.Add(this);
if(m_connected) Disconnect();
}
void TcpSocket::OnError(int errcode)
{
/* Bleh.. :p */
Disconnect();
}
bool TcpSocket::Writable()
{
return (m_writeBuffer->GetSize() > 0) ? true : false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -