Files
DBService/common/Socket.cpp
T
2026-07-09 11:27:59 +08:00

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);
}
}
//
//////////////////////////////////////////////////////////////////////////