606 lines
13 KiB
C++
606 lines
13 KiB
C++
#ifdef _WIN32
|
|
// #include <stdarg.h>
|
|
//#include <iostream>
|
|
#include <windows.h>
|
|
typedef int socklen_t;
|
|
#else //!WIN32
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "typedef.h"
|
|
#include "debug.h"
|
|
#include "Socket.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CSocket
|
|
//
|
|
CSocket::CSocket()
|
|
{
|
|
m_bOpen = false;
|
|
m_skt = 0;
|
|
}
|
|
|
|
CSocket::~CSocket()
|
|
{
|
|
int ret = 0;
|
|
if( IsOpen() ){
|
|
ret = Close();
|
|
}
|
|
|
|
if( m_skt>0 && ret==0 ){
|
|
closesocket (m_skt);
|
|
m_skt = 0;
|
|
}
|
|
else{
|
|
int err = GetLastError();
|
|
DebugPrint( "Close error code=%d.\n", err );
|
|
}
|
|
}
|
|
|
|
int CSocket::Close()
|
|
{
|
|
if( m_bOpen && m_skt>0 ){
|
|
m_bOpen = false;
|
|
return shutdown( m_skt, 0x02 );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool CSocket::GetLocalAddr(char *sAddr)
|
|
{
|
|
if (!sAddr) return false;
|
|
|
|
SOCKADDR_IN addr;
|
|
#ifdef __MACOSX__
|
|
UINT nSize = sizeof(addr);
|
|
#else
|
|
int nSize = sizeof(addr);
|
|
#endif
|
|
if (::getsockname(m_skt,(struct sockaddr*)&addr,(socklen_t*)&nSize)==SOCKET_ERROR)
|
|
return false;
|
|
char *pb=(char *)&(addr.sin_addr);
|
|
|
|
unsigned b1=(unsigned char)(*pb);
|
|
unsigned b2=(unsigned char)(*(pb+1));
|
|
unsigned b3=(unsigned char)(*(pb+2));
|
|
unsigned b4=(unsigned char)(*(pb+3));
|
|
sprintf(sAddr,"%d.%d.%d.%d",b1,b2,b3,b4);
|
|
return true;
|
|
}
|
|
|
|
bool CSocket::SetOption(int option,const void * valuePtr,unsigned int valueSize)
|
|
{
|
|
|
|
return (::setsockopt(m_skt,IPPROTO_IP,option,(char *)valuePtr,valueSize)==0);
|
|
}
|
|
|
|
int CSocket::SetNonblock( bool bNonblock )
|
|
{
|
|
int ret = 0;
|
|
|
|
DWORD fionbio = bNonblock;
|
|
if( ioctlsocket(m_skt, FIONBIO, &fionbio)==SOCKET_ERROR ){
|
|
ret = GetLastError();
|
|
DebugPrint("ioctlsocket Error = %d\n", ret );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int CSocket::WaitForReading(int nSeconds )
|
|
{
|
|
// SetNonblock( true );
|
|
|
|
// DebugPrint( "socket wait for reading.\n" );
|
|
fd_set rfd;
|
|
FD_ZERO(&rfd);
|
|
FD_SET(m_skt,&rfd);
|
|
|
|
timeval tv;
|
|
tv.tv_sec = nSeconds;//等待时间
|
|
tv.tv_usec = 0;
|
|
|
|
int ret;
|
|
// while( true ){
|
|
ret = select(m_skt+1, &rfd, NULL, NULL, &tv);
|
|
// if( ret==0 || ret==SOCKET_ERROR || FD_ISSET(m_skt, &rfd)){
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
// DebugPrint( "socket wait for reading return %d\n", ret );
|
|
|
|
if( ret==1 ){
|
|
if( !FD_ISSET(m_skt, &rfd) ){
|
|
// DebugPrint( "SetNonblock\n" );
|
|
// SetNonblock( false );
|
|
ret = SOCKET_ERROR;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CUDPSocket
|
|
//
|
|
CUDPSocket::CUDPSocket()
|
|
{
|
|
m_skt = socket (AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (m_skt == INVALID_SOCKET){
|
|
DebugPrint("Can't open UDP socket\n");
|
|
m_bOpen = false;
|
|
int nErrorCode = GetLastError();
|
|
return;
|
|
}
|
|
|
|
m_bOpen = true;
|
|
|
|
m_nPacketLen = 0;
|
|
m_nCur = 0;
|
|
}
|
|
|
|
CUDPSocket::CUDPSocket(unsigned short nPort,bool bRaw)
|
|
{
|
|
if( bRaw ){
|
|
m_skt = socket (AF_INET,SOCK_RAW,108);
|
|
}
|
|
else{
|
|
m_skt = socket (AF_INET,SOCK_DGRAM,0);
|
|
}
|
|
|
|
if (m_skt == INVALID_SOCKET){
|
|
DebugPrint("Can't open UDP socket\n");
|
|
m_bOpen = false;
|
|
int nErrorCode = GetLastError();
|
|
return;
|
|
}
|
|
|
|
SOCKADDR_IN local_sin;
|
|
memset(&local_sin, 0, sizeof(local_sin) );
|
|
|
|
local_sin.sin_family = AF_INET;
|
|
local_sin.sin_port = htons (nPort);
|
|
local_sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
if (bind (m_skt,(struct sockaddr *) &local_sin,sizeof (sockaddr)) == SOCKET_ERROR){
|
|
DebugPrint("Binding Error\n");
|
|
// Close();
|
|
return;
|
|
}
|
|
|
|
m_bOpen = true;
|
|
|
|
m_nPacketLen = 0;
|
|
m_nCur = 0;
|
|
}
|
|
|
|
CUDPSocket::CUDPSocket(unsigned int ipAddr,unsigned short nPort,bool bRaw)
|
|
{
|
|
if( bRaw ){
|
|
m_skt = socket (AF_INET,SOCK_RAW,108);
|
|
}
|
|
else{
|
|
m_skt = socket (AF_INET,SOCK_DGRAM,0);
|
|
}
|
|
|
|
if (m_skt == INVALID_SOCKET){
|
|
DebugPrint("Can't open UDP socket\n");
|
|
int nError=GetLastError();
|
|
DebugPrint("CUDPSocket::CUDPSocket Socket Error = %d\n",nError);
|
|
m_bOpen = false;
|
|
return;
|
|
}
|
|
/*
|
|
if( SetNonblock( true )!=0 ){
|
|
return;
|
|
}
|
|
*/
|
|
memset(&ptop, 0, sizeof(ptop) );
|
|
|
|
ptop.sin_family=AF_INET;
|
|
ptop.sin_addr.s_addr=ipAddr;
|
|
ptop.sin_port=htons(nPort);
|
|
/*
|
|
for(int bufLen=0;bufLen<8;bufLen++)
|
|
ptop.sin_zero[bufLen] = 0;
|
|
|
|
SetNonblock( false );
|
|
*/
|
|
m_bOpen = true;
|
|
|
|
m_nPacketLen = 0;
|
|
m_nCur = 0;
|
|
}
|
|
|
|
CUDPSocket::CUDPSocket(char *sOtherName,unsigned short nPort,bool bRaw)
|
|
{
|
|
CUDPSocket( inet_addr(sOtherName), nPort, bRaw );
|
|
}
|
|
|
|
bool CUDPSocket::Listen(unsigned int nAllowConn)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
unsigned int CUDPSocket::ReadBlock(char *sBuf,unsigned int nLen )
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
unsigned int nRemain=nLen;
|
|
char bufffer[MAX_UDP_PACKET_SIZE];
|
|
|
|
while (nRemain>0){
|
|
if (m_nCur>=m_nPacketLen){//需要读报
|
|
unsigned int nIpAddr;
|
|
unsigned short nPort;
|
|
|
|
if( (m_nPacketLen=ReadFrom(bufffer,MAX_UDP_PACKET_SIZE,nIpAddr,nPort))>0 ){
|
|
m_nCur=0;
|
|
}
|
|
else if( m_nPacketLen<=0 ){
|
|
DebugPrint( "ReadFrom error, Socket error=%d\n", GetLastError() );
|
|
}
|
|
else{
|
|
return (nLen-nRemain);
|
|
}
|
|
}
|
|
else{//从缓冲区中读取
|
|
unsigned int nReadLen=((m_nPacketLen-m_nCur)>=nRemain)?nRemain:(m_nPacketLen-m_nCur);
|
|
memcpy(sBuf+(nLen-nRemain),bufffer+m_nCur,nReadLen);
|
|
nRemain -= nReadLen;
|
|
m_nCur += nReadLen;
|
|
}
|
|
}
|
|
return (nLen-nRemain);
|
|
}
|
|
|
|
unsigned int CUDPSocket::ReadBlock(char *sBuf,unsigned int nLen, unsigned int &nIpAddr,unsigned short &nPort )
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
unsigned int nRemain=nLen;
|
|
char bufffer[MAX_UDP_PACKET_SIZE];
|
|
|
|
while (nRemain>0){
|
|
if (m_nCur>=m_nPacketLen){//需要读报
|
|
if ((m_nPacketLen=ReadFrom(bufffer,MAX_UDP_PACKET_SIZE,nIpAddr,nPort)))
|
|
m_nCur=0;
|
|
else return (nLen-nRemain);
|
|
}
|
|
else{//从缓冲区中读取
|
|
unsigned int nReadLen=((m_nPacketLen-m_nCur)>=nRemain)?nRemain:(m_nPacketLen-m_nCur);
|
|
memcpy(sBuf+(nLen-nRemain),bufffer+m_nCur,nReadLen);
|
|
nRemain -= nReadLen;
|
|
m_nCur += nReadLen;
|
|
}
|
|
}
|
|
return (nLen-nRemain);
|
|
}
|
|
|
|
unsigned int CUDPSocket::ReadFrom(char *sBuf, unsigned int nLen,unsigned int &nIpAddr,unsigned short &nPort)
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
sockaddr_in sockAddr;
|
|
// SOCKADDR_IN addr;
|
|
|
|
#ifdef __MACOSX__
|
|
UINT addrLen = sizeof(sockAddr);
|
|
#else
|
|
int addrLen = sizeof(struct sockaddr);
|
|
#endif
|
|
|
|
int nRead=::recvfrom(m_skt,sBuf,nLen,0,(struct sockaddr *)&sockAddr, (socklen_t*)&addrLen);
|
|
if (nRead!=SOCKET_ERROR) {
|
|
#ifdef _WIN32
|
|
nIpAddr = sockAddr.sin_addr.S_un.S_addr;
|
|
#else
|
|
nIpAddr = sockAddr.sin_addr.s_addr;
|
|
#endif
|
|
nPort = ntohs(sockAddr.sin_port);
|
|
|
|
// DebugPrint("recvfrom %s:%d", inet_ntoa(sockAddr.sin_addr), nPort);
|
|
}
|
|
|
|
// DebugPrint( "UDP Receive %dbytes data.\n", nRead );
|
|
|
|
return nRead;
|
|
}
|
|
|
|
unsigned int CUDPSocket::Peek(char *sBuf, unsigned int nLen)
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
sockaddr_in sockAddr;
|
|
|
|
#ifdef __MACOSX__
|
|
UINT addrLen = sizeof(sockAddr);
|
|
#else
|
|
int addrLen = sizeof(sockAddr);
|
|
#endif
|
|
|
|
int nRead=::recvfrom(m_skt,sBuf,nLen,MSG_PEEK,(struct sockaddr *)&sockAddr, (socklen_t*)&addrLen);
|
|
|
|
return nRead;
|
|
}
|
|
|
|
unsigned int CUDPSocket::SendTo(char *sBuf,unsigned int nLen, unsigned int nIpAddr,unsigned short nPort )
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
sockaddr_in sockAddr;
|
|
memset(&sockAddr, 0, sizeof(sockAddr) );
|
|
|
|
sockAddr.sin_family=AF_INET;
|
|
sockAddr.sin_addr.s_addr = nIpAddr;
|
|
sockAddr.sin_port = htons(nPort);
|
|
|
|
// DebugPrint("sendto %s:%d", inet_ntoa(sockAddr.sin_addr), nPort);
|
|
|
|
int nWrite = ::sendto(m_skt, (const char *)sBuf, nLen, 0, (struct sockaddr *)&sockAddr, sizeof(sockaddr) );
|
|
if (nWrite!=SOCKET_ERROR){
|
|
return nWrite;
|
|
}
|
|
else{
|
|
int nError=GetLastError();
|
|
DebugPrint("CUDPSocket::Send,Socket error = %d\n",nError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
unsigned int CUDPSocket::Send(char *sBuf,unsigned int nLen)
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
int nWrite = ::sendto(m_skt, (const char *)sBuf, nLen, 0, (struct sockaddr *)&ptop,sizeof(sockaddr));
|
|
if (nWrite!=SOCKET_ERROR){
|
|
return nWrite;
|
|
}
|
|
else{
|
|
int nError=GetLastError();
|
|
DebugPrint("PUDPSocket::Send,Socket error = %d\n",nError);
|
|
return 0;
|
|
}
|
|
}
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#define TCP_NODELAY 0x0001
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CTCPSocket
|
|
//
|
|
CTCPSocket::CTCPSocket()
|
|
{
|
|
|
|
if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){
|
|
DebugPrint("Can't open tcp socket\n");
|
|
return;
|
|
}
|
|
/*
|
|
if( SetNonblock( true )!=0 )
|
|
return;
|
|
*/
|
|
int yes = 1;
|
|
|
|
setsockopt( m_skt, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes) );
|
|
setsockopt( m_skt, SOL_SOCKET, SO_KEEPALIVE, (char *)&yes, sizeof(yes) );
|
|
setsockopt( m_skt, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0 );
|
|
setsockopt( m_skt, SOL_SOCKET, SO_OOBINLINE, (char *)&yes, sizeof(yes) );
|
|
|
|
#ifdef SO_NOSIGPIPE
|
|
#ifndef MSG_NOSIGNAL
|
|
setsockopt( m_skt, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes) );
|
|
#endif
|
|
#endif
|
|
|
|
m_bOpen = true;
|
|
}
|
|
|
|
CTCPSocket::CTCPSocket(unsigned short nPort)
|
|
{
|
|
if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){
|
|
DebugPrint("Can't open tcp socket\n");
|
|
m_bOpen = false;
|
|
return;
|
|
}
|
|
|
|
SOCKADDR_IN local_sin;
|
|
local_sin.sin_family = AF_INET;
|
|
local_sin.sin_port = htons (nPort);
|
|
local_sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
if (bind (m_skt,(struct sockaddr *) &local_sin,sizeof (local_sin)) == SOCKET_ERROR){
|
|
DebugPrint("Binding Error\n");
|
|
// Close();
|
|
return;
|
|
}
|
|
m_bOpen = true;
|
|
}
|
|
|
|
|
|
CTCPSocket::CTCPSocket(char *sOtherName,unsigned short nPort)
|
|
{
|
|
|
|
if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){
|
|
DebugPrint("Can't open tcp socket\n");
|
|
m_bOpen = false;
|
|
return;
|
|
}
|
|
|
|
int yes = 1;
|
|
|
|
setsockopt(m_skt, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes));
|
|
setsockopt(m_skt, SOL_SOCKET, SO_KEEPALIVE, (char *)&yes, sizeof(yes));
|
|
setsockopt (m_skt, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0);
|
|
setsockopt (m_skt, SOL_SOCKET, SO_OOBINLINE, (char *)&yes, sizeof(yes));
|
|
|
|
m_bOpen = Connect( inet_addr(sOtherName), nPort );
|
|
}
|
|
|
|
bool CTCPSocket::Listen(unsigned int nAllowConn)
|
|
{
|
|
if (listen (m_skt,nAllowConn) == SOCKET_ERROR){
|
|
DebugPrint("Listening to the client failed.\n");
|
|
// Close();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CTCPSocket::Accept(CTCPSocket *pServerSkt)
|
|
{
|
|
sockaddr accept_sin;
|
|
|
|
#ifdef __MACOSX__
|
|
UINT nAcptSinLen = sizeof (accept_sin);
|
|
#else
|
|
int nAcptSinLen = sizeof (accept_sin);
|
|
#endif
|
|
|
|
m_skt = accept(pServerSkt->GetSocket(), (struct sockaddr *)&accept_sin, (socklen_t*)&nAcptSinLen);
|
|
|
|
if (m_skt == INVALID_SOCKET) {
|
|
DebugPrint("Accepting connection with client failed\n");
|
|
return false;
|
|
}
|
|
|
|
m_bOpen = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTCPSocket::Connect(unsigned int nIpAddr,unsigned short nPort)
|
|
{
|
|
if( m_skt==-1 ) return false;
|
|
|
|
SetNonblock( true );
|
|
|
|
SOCKADDR_IN dest_sin;
|
|
dest_sin.sin_family = AF_INET;
|
|
dest_sin.sin_port = htons (nPort);
|
|
dest_sin.sin_addr.s_addr = nIpAddr;
|
|
|
|
int nError = connect( m_skt,(PSOCKADDR)&dest_sin,sizeof (dest_sin));
|
|
if( nError==SOCKET_ERROR ){
|
|
nError = WSAGetLastError();
|
|
#ifdef _WIN32
|
|
if( nError!=WSAEWOULDBLOCK ){
|
|
#else
|
|
if( nError!=EINPROGRESS ){
|
|
#endif
|
|
DebugPrint("Connecting to the server connect error. code=%d\n", nError );
|
|
m_bOpen = false;
|
|
// closesocket( m_skt );
|
|
// m_skt = -1;
|
|
return false;
|
|
}
|
|
|
|
fd_set fdWr;
|
|
FD_ZERO(&fdWr);
|
|
FD_SET(m_skt,&fdWr);
|
|
|
|
timeval tv;
|
|
tv.tv_sec = 5;//等待5秒钟
|
|
tv.tv_usec = 0;
|
|
|
|
nError = select(m_skt+1, NULL, &fdWr, NULL, &tv);
|
|
|
|
if( nError==0 ){
|
|
DebugPrint("Connecting to the server time out.\n");
|
|
m_bOpen = false;
|
|
return false;
|
|
}
|
|
else if( nError==SOCKET_ERROR || !FD_ISSET(m_skt, &fdWr) ){
|
|
nError = WSAGetLastError();
|
|
DebugPrint("Connecting to the server select error. code=%d\n", nError);
|
|
m_bOpen = false;
|
|
// closesocket( m_skt );
|
|
// m_skt = -1;
|
|
|
|
return false;
|
|
}
|
|
else{
|
|
DebugPrint( "Connecting select return %d\n", nError );
|
|
}
|
|
}
|
|
else{
|
|
DebugPrint( "Tcp connect return %d\n", nError );
|
|
}
|
|
|
|
SetNonblock( false );
|
|
|
|
return true;
|
|
}
|
|
|
|
unsigned int CTCPSocket::ReadBlock(char *sBuf,unsigned int nLen)
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
unsigned int nReturn = recv (m_skt, sBuf, nLen, 0);
|
|
|
|
if( nReturn==0 ){
|
|
DebugPrint( "Socket has been shutdown by remote.\n" );
|
|
// Close();
|
|
|
|
return 0;
|
|
}
|
|
|
|
if( nReturn==SOCKET_ERROR ){
|
|
int err = WSAGetLastError();
|
|
DebugPrint("Socket error, code=%d\n", err);
|
|
// Close();
|
|
|
|
return 0;
|
|
}
|
|
DebugPrint( "TCP Receive %dbytes data.\n", nReturn );
|
|
|
|
return nReturn;
|
|
}
|
|
unsigned int CTCPSocket::Send(char *sBuf,unsigned int nLen)
|
|
{
|
|
if (!m_bOpen) return 0;
|
|
|
|
unsigned nReturn = send( m_skt, sBuf, nLen, 0 );
|
|
if (nReturn == SOCKET_ERROR){
|
|
int err = WSAGetLastError();
|
|
DebugPrint("Sending data to the client failed. err=%d\n", err);
|
|
// Close();
|
|
|
|
return -1;
|
|
}
|
|
return nReturn;
|
|
}
|
|
|
|
void CTCPSocket::GetPeerAddr(char *sAddr)
|
|
{
|
|
sockaddr_in addr;
|
|
|
|
#ifdef __MACOSX__
|
|
UINT size = sizeof(addr);
|
|
#else
|
|
int size = sizeof(addr);
|
|
#endif
|
|
|
|
if (getpeername(m_skt,(struct sockaddr *)&addr,(socklen_t*)&size)==SOCKET_ERROR)
|
|
strcpy(sAddr,"");
|
|
else{
|
|
char *pb=(char *)&(addr.sin_addr);
|
|
unsigned b1=(unsigned char)(*pb);
|
|
unsigned b2=(unsigned char)(*(pb+1));
|
|
unsigned b3=(unsigned char)(*(pb+2));
|
|
unsigned b4=(unsigned char)(*(pb+3));
|
|
sprintf(sAddr,"%d.%d.%d.%d",b1,b2,b3,b4);
|
|
}
|
|
}
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|