见 socketmethod.h 和socketmethod.cpp代码以及注释,Visual Studio新建一个控制台程序,加入这两个文件,配置类型选为动态库(.dll),编译即可。
socketmethod.h
/*This file provides basic windows socket methods*/
#pragma once
#ifdef _DLL_EXPORTS
#define DLL_API _declspec(dllexport)
#else
#define DLL_API _declspec(dllimport)
#endif // _DLL_EXPORTS
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <vector>
namespace SocketMethod {
class SocketServer {
public:
SocketServer(int PORT);
~SocketServer();
//Get the error code when initing
virtual int GetErrorCode();
//Close the server socket
virtual void CloseSocketServer();
//Close a client socket
virtual void CloseSocketConn(SOCKET skt);
//Clean all
virtual void CleanSocket();
//Clean all Socket Clients
virtual void CleanSocketClients();
//Wait for client to connect to this server.
//If a connection comes it will be pushed to m_ClientSocketArray
virtual SOCKET WaitAccept();
//Get connected clients sockets of this server
virtual std::vector<SOCKET> GetConnectedClients();
//Get the Socket of this server
virtual SOCKET GetSocketServer();
//The buf needs to be malloced outside with size
virtual bool Send(SOCKET sockConn, char* buf, int size);
template<typename T>
void FreeBasicArray(T& Array);
//The recvBuf needs to be malloced outside with size.
//If tcp error occured inside,recvBuf will be deleted and set nullptr.
virtual void Receive(SOCKET sockConn, char*& recvBuf, unsigned int size);
private:
//The default port is 8001
int m_DEFAULT_PORT = 8001;
WORD m_wVersionRequested;
WSADATA m_wsaData;
int m_err, m_iLen;
SOCKET m_sockSrv;
SOCKADDR_IN m_addrSrv;
SOCKET m_sockConn;
int m_CurrentSize = 0;
std::vector<SOCKET> m_ClientSocketArray;
//State of initing process,0: no error, ohters:error
int m_error = 0;
//Init the socket server.
//If fails returns -1
int initSocketServer(int port);
};
template<typename T>
inline void SocketServer::FreeBasicArray(T& Array) {
if (Array != nullptr) {
delete[] Array;
Array = nullptr;
}
}
class SocketClient
{
//TCP_SOCKET����
private:
WORD wVersionRequested;
WSADATA wsaData;
int err = 0, iLen = 0;
int DEFAULT_PORT = 8001;
SOCKET sockClt = 0;
template<typename T>
void FreeBasicArray(T& Array);
public:
//Init a socket client.
//if error occurs,err will be set.
SocketClient(int PORT = 8001);
~SocketClient();
//Get the socket of this client
virtual SOCKET GetSocket();
//Get the error when initing
virtual int GetError();
//The buf needs to be malloced outside with size
virtual bool Send(SOCKET sockConn, char* buf, int size);
//The recvBuf needs to be malloced outside with size.
//If tcp error occured inside,recvBuf will be deleted and set nullptr.
virtual void Receive(SOCKET sockConn, char*& recvBuf, unsigned int size);
//Close a client socket
virtual void CloseSocketConn(SOCKET skt);
};
template<typename T>
inline void SocketClient::FreeBasicArray(T& Array) {
if (Array != nullptr) {
delete[] Array;
Array = nullptr;
}
}
//Create a Socket Server Inside Using new,UNABLE to delete it outside.
//Use ReleaseSocketServer(SocketServer* sc) to release it.
extern "C" DLL_API SocketServer * CreateSocketServer(int PORT);
//Create a Socket Client Inside Using new,UNABLE to delete it outside.
//Use ReleaseSocketClient(SocketClient* sc) to release it.
extern "C" DLL_API SocketClient * CreateSocketClient(int PORT);
//ReleaseSocketClient will destroy the SocketClient Object,and close socket.
extern "C" DLL_API void ReleaseSocketClient(SocketClient * sc);
//ReleaseSocketServer will destroy the SocketServer Object,and close all sockets,clean up.
extern "C" DLL_API void ReleaseSocketServer(SocketServer * sc);
}
socketmethod.cpp
#define _DLL_EXPORTS
#include "socketmethod.h"
namespace SocketMethod {
SocketServer::SocketServer(int PORT) {
initSocketServer(PORT);
}
SocketServer::~SocketServer() {
CleanSocketClients();
CloseSocketServer();
CleanSocket();
}
int SocketServer::GetErrorCode()
{
return m_error;
}
void SocketServer::CloseSocketServer() {
closesocket(m_sockSrv);
}
void SocketServer::CloseSocketConn(SOCKET skt) {
closesocket(skt);
}
void SocketServer::CleanSocket() {
WSACleanup();
}
void SocketServer::CleanSocketClients()
{
for (auto it = m_ClientSocketArray.begin(); it != m_ClientSocketArray.end(); it++) {
closesocket(*it);
}
}
SOCKET SocketServer::WaitAccept() {
SOCKADDR_IN addrClt;
int len = sizeof(SOCKADDR);
SOCKET sockConn = accept(m_sockSrv, (SOCKADDR*)&addrClt, &len);
m_ClientSocketArray.push_back(sockConn);
return sockConn;
}
std::vector<SOCKET> SocketServer::GetConnectedClients()
{
return m_ClientSocketArray;
}
SOCKET SocketServer::GetSocketServer() {
return m_sockSrv;
}
bool SocketServer::Send(SOCKET sockConn, char* buf, int size) {
if (!(::send(sockConn, buf, size, 0) > 0)) {
return false;
}
return true;
}
void SocketServer::Receive(SOCKET sockConn, char*& recvBuf, unsigned int size) {
int len_want = size;
int len_received = 0;
while (1) {
int iLen = recv(sockConn, recvBuf + len_received, len_want, 0);
if (iLen == 0) {
FreeBasicArray(recvBuf);
break;
}
if (iLen == -1) {
FreeBasicArray(recvBuf);
break;
}
len_received += iLen; //�ݼ�
len_want -= iLen;
if (len_want == 0) {
len_want = size;
len_received = 0;
break;
}
}
}
int SocketServer::initSocketServer(int port) {
m_wVersionRequested = MAKEWORD(2, 2);//create 16bit data
m_err = ::WSAStartup(m_wVersionRequested, &m_wsaData); //load win socket
if (m_err != 0)
{
return -1;
}
m_DEFAULT_PORT = port;
m_addrSrv.sin_family = AF_INET;
m_addrSrv.sin_addr.s_addr = ::htonl(INADDR_ANY);//Auto IP, byte sequence change
m_addrSrv.sin_port = ::htons(m_DEFAULT_PORT);
m_sockSrv = ::socket(AF_INET, SOCK_STREAM, 0);
//(4)bind
m_err = ::bind(m_sockSrv, (SOCKADDR*)&m_addrSrv, sizeof(SOCKADDR));
if (m_err != 0)
{
return -2;
}
m_err = ::listen(m_sockSrv, 5);
if (m_err != 0)
{
return -3;
}
return 0;
}
SocketClient::SocketClient(int PORT) {
DEFAULT_PORT = PORT;
wVersionRequested = MAKEWORD(2, 2);//create 16bit data
//(1)Load WinSock
err = WSAStartup(wVersionRequested, &wsaData); //load win socket
if (err != 0)
{
err = -1;
return;
}
//(2)create socket
sockClt = socket(AF_INET, SOCK_STREAM, 0);
if (sockClt == INVALID_SOCKET) {
err = -2;
return;
}
//(3)IP
SOCKADDR_IN addrSrv;
addrSrv.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &addrSrv.sin_addr.S_un.S_addr);
addrSrv.sin_port = htons(DEFAULT_PORT);
//(5)connect
err = connect(sockClt, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (err == INVALID_SOCKET)
{
err = -3;
return;
}
//TCP_SOCKET����
}
SocketClient::~SocketClient()
{
closesocket(sockClt);
}
SOCKET SocketClient::GetSocket() {
return sockClt;
}
int SocketClient::GetError() {
return err;
}
bool SocketClient::Send(SOCKET sockConn, char* buf, int size) {
if (!(::send(sockConn, buf, size, 0) > 0)) {
return false;
}
return true;
}
void SocketClient::Receive(SOCKET sockConn, char*& recvBuf, unsigned int size) {
int len_want = size;
int len_received = 0;
while (1) {
int iLen = recv(sockConn, recvBuf + len_received, len_want, 0);
if (iLen == 0) {
FreeBasicArray(recvBuf);
break;
}
if (iLen == -1) {
FreeBasicArray(recvBuf);
break;
}
len_received += iLen; //�ݼ�
len_want -= iLen;
if (len_want == 0) {
len_want = size;
len_received = 0;
break;
}
}
}
void SocketClient::CloseSocketConn(SOCKET skt) {
closesocket(skt);
}
extern "C" DLL_API SocketServer * CreateSocketServer(int PORT) {
return new SocketServer(PORT);
}
extern "C" DLL_API SocketClient * CreateSocketClient(int PORT) {
return new SocketClient(PORT);
}
extern "C" DLL_API void ReleaseSocketClient(SocketClient * sc)
{
if (sc != nullptr)
{
delete sc;
sc = nullptr;
}
}
DLL_API void ReleaseSocketServer(SocketServer* ss)
{
if (ss != nullptr)
{
delete ss;
ss = nullptr;
}
}
}
注意事项:
1.#define _DLL_EXPORTS要放在#include "socketmethod.h" 前面。
2.使用命名空间。
说明:
这种方式导出是实际工程中用的最广泛的方式。