Win32 程序设计-TCP/IP

一、端口互斥操作类

#ifndef _LOCK_H_
#define _LOCK_H_

#include <windows.h>

//this can be used in inter process situation.
class InterLock
{
public:
	InterLock()
	{
		InitializeCriticalSection(&cs_);
	}

	~InterLock()
	{
		DeleteCriticalSection(&cs_);
	}

	void enter()
	{
		EnterCriticalSection(&cs_);
	}

	void leave()
	{
		LeaveCriticalSection(&cs_);		
	}
private:
	CRITICAL_SECTION cs_;
};

template <typename LockType>
class AutoLock
{
public:
	AutoLock(LockType& lock) : lock_(lock)
	{
		lock_.enter();
	}

	~AutoLock()
	{
		lock_.leave();
	}
private:
	LockType& lock_;
};

#endif

二、服务端

2.1 头文件:SocketServer.h

只维护一个客户端,心跳超多10S没有连接就断开

#ifndef _SOCKETSERVER_H_
#define _SOCKETSERVER_H_

#define MAX_FRAME_BUF 100*1024

class CSocketServer
{
private:
	SOCKET listenSocket; 
	static SOCKET acceptSocket;

	HANDLE acceptthread;
	volatile bool acceptthreadrunnable;

	HANDLE rcvshakehandthread;
	volatile bool rcvshakehandthreadrunnable;

private:
	BYTE srcframeBuf[MAX_FRAME_BUF];
	BYTE dstframeBuf[MAX_FRAME_BUF];
	int dstframeBufLen;
	static unsigned int currentFrameLen ;
	static int iState;
	static DWORD lastshakehandTime;

private:
	CSocketServer(void);
	static CSocketServer* instance;

public:
	static CSocketServer* GetInstance();
	~CSocketServer(void);

	bool Start(unsigned int port);
	bool Stop();
	bool SndMessage(const unsigned char* buf, int buflen);
	bool RcvMessage(unsigned char* buf, int buflen, int& rcvlen);
	void SetRcvShaveHand();
private:
	static DWORD WINAPI acceptThread(LPVOID lpParameter);	
	static DWORD WINAPI rcvshakeHandThread(LPVOID lpParameter);

public:
	void closeSocket(SOCKET& s);

};

#endif

2.2 实现端:SocketServer.cpp


CSocketServer::CSocketServer(void)
{
	listenSocket = INVALID_SOCKET;

	acceptthreadrunnable = false;
	acceptthread = NULL;

	rcvshakehandthreadrunnable = false;
	rcvshakehandthread = NULL;

	WSADATA wsaData;
	int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if (iResult != NO_ERROR)
	{			
		//printf("Error at WSAStartup()\n");			
	}
}

CSocketServer::~CSocketServer(void)
{
	WSACleanup();
}

void CSocketServer::closeSocket(SOCKET& s)
{
	if (s != INVALID_SOCKET && s != SOCKET_ERROR)
	{
		shutdown(s, SD_BOTH);
		closesocket(s);
		s = INVALID_SOCKET;
	}
}


SOCKET CSocketServer::acceptSocket = INVALID_SOCKET;
unsigned int CSocketServer::currentFrameLen = 0;
int CSocketServer::iState = 1;
DWORD CSocketServer::lastshakehandTime = -1;
CSocketServer* CSocketServer::instance = new CSocketServer();
CSocketServer* CSocketServer::GetInstance()
{
	return instance;
}

bool CSocketServer::Start(unsigned int port)
{
	listenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
	if (listenSocket == INVALID_SOCKET)
	{
		return false;
	}

	sockaddr_in saServer;

	saServer.sin_family = AF_INET;
	saServer.sin_addr.s_addr = htonl(INADDR_ANY); 
	//saServer.sin_addr.s_addr = inet_addr( "192.168.1.150"); 
	saServer.sin_port = htons(port);

	if ( bind( listenSocket, (SOCKADDR*) &saServer, sizeof(saServer) ) == SOCKET_ERROR ) 
	{	
		return false;
	}
	if ( listen( listenSocket, 1 ) == SOCKET_ERROR )
	{
		return false;
	}

	acceptthreadrunnable = true;
	acceptthread = CreateThread(NULL, 0, acceptThread, this, 0, NULL);

	lastshakehandTime = -1;
	rcvshakehandthreadrunnable = true;
	rcvshakehandthread = CreateThread(NULL, 0, rcvshakeHandThread, this, 0, NULL);


	if (gbPDACommStatus)
	{
		WriteDebugInfo("start success\n");
	}

	return true;
}

DWORD WINAPI CSocketServer::rcvshakeHandThread(LPVOID lpParameter)
{
	CSocketServer* server = (CSocketServer*)lpParameter;

	while ( server->rcvshakehandthreadrunnable)
	{
		if (lastshakehandTime != -1 && GetTickCount() - lastshakehandTime > 10*1000)
		{
			server->closeSocket(acceptSocket);
			if (gbPDACommStatus)
			{
				WriteDebugInfo("disconnect\n");
			}
		}
		Sleep(3000);
	}

	return 0;
}

DWORD WINAPI CSocketServer::acceptThread(LPVOID lpParameter)
{
	CSocketServer* server = (CSocketServer*)lpParameter;		

	sockaddr_in acceptAddress;
	int adressLen;

	SOCKET tmpSocket = INVALID_SOCKET;
	while ( server->acceptthreadrunnable)
	{
		adressLen = sizeof(acceptAddress);
		tmpSocket = accept( server->listenSocket, (SOCKADDR*) &acceptAddress, &adressLen );

		if (acceptSocket == INVALID_SOCKET || acceptSocket == SOCKET_ERROR)
		{
			if (gbPDACommStatus)
			{
				WriteDebugInfo("new connect\n");
			}
			acceptSocket = tmpSocket;
			lastshakehandTime = GetTickCount();
			currentFrameLen = 0;
			iState = 1;
		}
		else
		{
			server->closeSocket(tmpSocket);
		}

	}
	return 0;	

}

bool CSocketServer::Stop()
{
	acceptthreadrunnable = false;
	rcvshakehandthreadrunnable = false;

	closeSocket(listenSocket);
	closeSocket(acceptSocket);

	WaitForSingleObject(acceptthread, 5000);
	WaitForSingleObject(rcvshakehandthread, 5000);
	if (acceptthread != NULL)
	{
		CloseHandle(acceptthread);
	}
	if (rcvshakehandthread != NULL)
	{
		CloseHandle(rcvshakehandthread);
	}
	if (gbPDACommStatus)
	{
		WriteDebugInfo("stop server\n");
	}

	return true;
}

InterLock serverSndLock;
bool CSocketServer::SndMessage(const unsigned char* buf, int buflen)
{
	AutoLock<InterLock> autoLock(serverSndLock);

	if (acceptSocket == INVALID_SOCKET || acceptSocket == SOCKET_ERROR)
	{
		return false;
	}

	int rc = send(acceptSocket, (char*)(buf), buflen, 0);
	if(rc == SOCKET_ERROR)
	{
		if (gbPDACommStatus)
		{
			WriteDebugInfo("snd error\n");
		}
		closeSocket(acceptSocket);
		return false;
	}

	if (gbPDACommData)
	{
		WriteDebugInfo("snd %d\n", buflen);
		WriteDebugInfo(buflen, buf);
		WriteDebugInfo("\n");
	}

	return true;
}

InterLock serverRcvLock;
bool CSocketServer::RcvMessage(unsigned char* buf, int buflen, int& rcvlen)
{
	AutoLock<InterLock> autoLock(serverRcvLock);

	if (acceptSocket == INVALID_SOCKET || acceptSocket == SOCKET_ERROR)
	{
		return false;
	}

	fd_set          readfds;
	struct timeval  timeout;

	timeout.tv_sec = 1000 / 1000u;
	timeout.tv_usec = (1000 % 1000u) * 1000u;

	FD_ZERO(&readfds);

	FD_SET(acceptSocket, &readfds);
	int rc = select(-1, &readfds, NULL, NULL, &timeout);
	if (rc == SOCKET_ERROR)
	{
		if (gbPDACommStatus)
		{
			WriteDebugInfo("select error\n");
		}
		closeSocket(acceptSocket);
		return false;
	}
	else if (rc == 0)
	{
		rcvlen = 0;
		return false;
	}

	rc = recv(acceptSocket, (char*)buf, buflen, 0);
	if (rc == SOCKET_ERROR || rc == 0)
	{
		if (gbPDACommStatus)
		{
			WriteDebugInfo("recv error\n");
		}
		closeSocket(acceptSocket);
		return false;
	}

	if (gbPDACommData)
	{
		WriteDebugInfo("rcv %d\n", rc);
		WriteDebugInfo(rc, buf);
		WriteDebugInfo("\n");
	}

	rcvlen = rc;

	return true;
}

void CSocketServer::SetRcvShaveHand()
{
	lastshakehandTime = GetTickCount();
}

2.3 对外发布接口封装

bool WINAPI TCPServer_Start(unsigned short port)
{

	if ( port < 0 || port > 65535 )
	{
		return false;
	}

	return CSocketServer::GetInstance()->Start(port);
}

bool WINAPI TCPServer_Stop()
{
	return CSocketServer::GetInstance()->Stop();
}

bool WINAPI TCPServer_Send(const unsigned char* buf, int buflen)
{
	if ( buf == NULL)
	{
		return false;
	}

	return CSocketServer::GetInstance()->SndMessage(buf, buflen);
}


bool WINAPI TCPServer_Recv(unsigned char* buf, int buflen, int& rcvlen)
{
	if ( buf == NULL)
	{
		return false;
	}

	return CSocketServer::GetInstance()->RcvMessage(buf, buflen, rcvlen);

}

void WINAPI SetRcvShaveHand()
{
	CSocketServer::GetInstance()->SetRcvShaveHand();
}

三、客户端

3.1 头文件:SocketClient.h

#ifndef _SOCKETCLIENT_H_
#define _SOCKETCLIENT_H_

class CSocketClient
{
private:
	SOCKET m_socket;

public:
	static CSocketClient* GetInstance();

	~CSocketClient(void);

	bool Connect(const char* ipAddress,unsigned short port);
	bool DisConnect();
	bool SndMessage(const unsigned char* buf, int buflen);
	bool RcvMessage(unsigned char* buf, int buflen, int& rcvlen);
private:
	CSocketClient(void);
	static CSocketClient* instance;

};

#endif

3.2 实现:SocketClient.cpp

CSocketClient::CSocketClient(void)
{
	m_socket = INVALID_SOCKET;
}

CSocketClient::~CSocketClient(void)
{
	DisConnect();
}

CSocketClient* CSocketClient::instance = new CSocketClient();
CSocketClient* CSocketClient::GetInstance()
{
	return instance;
}

bool CSocketClient::Connect(const char* ipAddress,unsigned short port)
{
	if (m_socket != INVALID_SOCKET)
	{
		return false;
	}
	int                         Flag;
	WSADATA wsaData;
	struct sockaddr_in          Sin;


	int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if (iResult != NO_ERROR) 
	{
		printf("WSAStartup failed with error: %d\n", iResult);
		return false;
	}

	m_socket = socket(AF_INET, SOCK_STREAM, 0);
	if(INVALID_SOCKET == m_socket)
	{
		printf("socket failed with error: %ld\n", WSAGetLastError());
		WSACleanup();
		return false;
	}

	memset(&Sin, 0, sizeof Sin);
	Sin.sin_family = AF_INET;
	Sin.sin_addr.s_addr = inet_addr(ipAddress);
	Sin.sin_port = htons(port);

	iResult = connect(m_socket, (struct sockaddr *)&Sin, sizeof(Sin));

	if( 0 > iResult )
	{
		closesocket(m_socket);
		WSACleanup();
		m_socket = INVALID_SOCKET;
		return false;
	}

	setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&Flag, sizeof Flag);

	return true;
}

bool CSocketClient::DisConnect()
{
	if (m_socket == INVALID_SOCKET)
	{
		return true;
	}

	shutdown(m_socket,SD_BOTH);
	closesocket(m_socket);
	WSACleanup();
	m_socket = INVALID_SOCKET;

	return true;
}

InterLock clientSndLock;
bool CSocketClient::SndMessage(const unsigned char* buf, int buflen)
{
	AutoLock<InterLock> autoLock(clientSndLock);

	if (m_socket == INVALID_SOCKET)
	{
		return false;
	}

	int havesnd = 0;

	while (havesnd < buflen)
	{
		int rc = send(m_socket, (char*)(buf + havesnd), buflen-havesnd, 0);
		if(rc == SOCKET_ERROR)
		{
			return false;
		}
		havesnd += buflen;
	}

	return true;
}

InterLock clientRcvLock;
bool CSocketClient::RcvMessage(unsigned char* buf, int buflen, int& rcvlen)
{
	AutoLock<InterLock> autoLock(clientRcvLock);

	if (m_socket == INVALID_SOCKET)
	{
		return false;
	}

	fd_set          readfds;
	struct timeval  timeout;

	timeout.tv_sec = 1000 / 1000u;
	timeout.tv_usec = (1000 % 1000u) * 1000u;

	FD_ZERO(&readfds);

	FD_SET(m_socket, &readfds);
	int rc = select(-1, &readfds, NULL, NULL, &timeout);
	if (rc < 0)
	{
		return false;
	}
	else if (rc == 0)
	{
		rcvlen = 0;
		return 0;
	}

	rc = recv(m_socket, (char*)buf, buflen, 0);
	if (rc <= 0)
	{
		return false;
	}

	rcvlen = rc;

	return 0;
}

3.3 接口封装

bool WINAPI TCPClient_Connect(const char* ipAddress,unsigned short port)
{
	if (ipAddress == NULL)
	{
		return false;
	}

	if (CCommonFunc::GetInstance()->isRightIPAddress(ipAddress) != 0)
	{
		return false;
	}
	
	if ( port < 0 || port > 65535 )
	{
		return false;
	}

	return CSocketClient::GetInstance()->Connect(ipAddress, port);

}

bool WINAPI TCPClient_DisConnect()
{
	return CSocketClient::GetInstance()->DisConnect();
}

bool WINAPI TCPClient_Send(const unsigned char* buf, int buflen)
{
	if ( buf == NULL)
	{
		return false;
	}

	return CSocketClient::GetInstance()->SndMessage(buf, buflen);
}

bool WINAPI TCPClient_Recv(unsigned char* buf, int buflen, int& rcvlen)
{
	if ( buf == NULL)
	{
		return false;
	}

	return CSocketClient::GetInstance()->RcvMessage(buf, buflen, rcvlen);
}

发表回复