支持WIN32、Linux通信Socket简易封装
注:_WIN32实在MFC基础上封装的,可以去掉_WIN32部分。
一、封装.h.cpp
头文件Socket.h
#ifndef SOCKET_H
#define SOCKET_H
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <string>
typedef int socklen_t;
#else
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define INVALID_SOCKET -1
typedef int SOCKET;
#endif // _WIN32
class Socket
{
SOCKET m_hSocket;
public:
#ifdef _WIN32
Socket(SOCKET sock = INVALID_SOCKET) : m_hSocket(sock)
{
static WSAData wd;
if (wd.wVersion == 0)
WSAStartup(0x0202, &wd);
}
#else
Socket(){};
Socket(int sock) : m_hSocket(sock){};
#endif // _WIN32
~Socket()
{
if (INVALID_SOCKET != m_hSocket)
{
#ifdef _WIN32
closesocket(m_hSocket);
#else
close(m_hSocket);
#endif // _WIN32
}
}
operator SOCKET() const
{
return m_hSocket;
}
//输出Error Info
inline static void GetLastError()
{
#ifdef _WIN32
auto n = WSAGetLastError();
printf("erron:%d\n", n);
WSASetLastError(n);
#else
printf("erron:%d info:%s\n", errno, strerror(errno));
#endif // _WIN32
}
//创建连接,
//nSocketPort端口号、nSocketType连接模式(默认TCP)、
//lpszSocketAddress选择创建链接的IP地址(默认0.0.0.0)
bool Create(unsigned int nSocketPort = 0, int nSocketType = SOCK_STREAM, const char *lpszSocketAddress = NULL);
//启动TCP服务端后、进行监听
//nBacklog 挂起连接队列的最大长度。
inline bool Listen(int nBacklog = 5)
{
return listen(m_hSocket, nBacklog);
}
//等待连接
bool Accept(Socket &socka, char *sIP = nullptr, unsigned int *pPort = nullptr);
//链接到对应IP、端口
bool Connect(const char *lpszHostAddress, unsigned int nHostPort);
//返回当前IP、主机端口info
bool GetSockName(char *sIP, unsigned int &nPort);
bool GetSockName(std::string &sIP, unsigned int &nPort);
//返回Peer的IP、端口Info
bool GetPeerName(char *sIP, unsigned int &nPort);
bool GetPeerName(std::string &sIP, unsigned int &nPort);
//关闭Socket
inline void Close()
{
#ifdef _WIN32
closesocket(m_hSocket);
#else
close(m_hSocket);
#endif // _WIN32
m_hSocket = INVALID_SOCKET;
}
//接受buffer
//lpBuf buffer地址 、 nBufLen buffer长度
inline int Receive(void *lpBuf, int nBufLen, int nFlags = 0)
{
return recv(m_hSocket, static_cast<char *>(lpBuf), nBufLen, nFlags);
}
//接受buffer
// sockfd socket句柄
inline int RecvFrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
#ifdef _WIN32
return recvfrom(sockfd, static_cast<char*>(buf), len, flags, src_addr, addrlen);
#else
return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
#endif // _WIN32
}
int ReceiveFrom(void *lpBuf, int nBufLen,
char *sIP = nullptr, unsigned int *pPort = nullptr, int nFlags = 0);
//发送buffer
//lpBuf发送内容、nBufLen buffer长度
inline int Send(const void *lpBuf, int nBufLen, int nFlags = 0)
{
return send(m_hSocket, static_cast<const char *>(lpBuf), nBufLen, nFlags);
}
//dest_addr目标IP
inline int Sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
#ifdef _WIN32
return sendto(sockfd, static_cast<const char *>buf, len, flags, dest_addr, addrlen);
#else
return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
#endif // _WIN32
}
//nHostPort目标端口、lpszHostAddress目标IP
int SendTo(const void *lpBuf, int nBufLen,
unsigned int nHostPort, char *lpszHostAddress, int nFlags = 0);
};
#endif // !SOCKET_H
实现文件Socket.cpp
#include "Socket.h"
bool Socket::Create(unsigned int nSocketPort, int nSocketType, const char *lpszSocketAddress)
{
m_hSocket = socket(AF_INET, nSocketType, IPPROTO_IP);
if (INVALID_SOCKET == m_hSocket)
{
GetLastError();
Close();
return false;
}
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(nSocketPort);
if (lpszSocketAddress)
{
#ifdef _WIN32
sa.sin_addr.S_un.S_addr = inet_addr(lpszSocketAddress);
#else
sa.sin_addr.s_addr = inet_addr(lpszSocketAddress);
#endif // _WIN32
}
else
sa.sin_addr.s_addr = INADDR_ANY;
int n = bind(m_hSocket, (sockaddr *)&sa, sizeof(sa));
if (n)
{
GetLastError();
Close();
return false;
}
return true;
}
bool Socket::Accept(Socket &socka, char *sIP, unsigned int *pPort)
{
if (sIP || pPort)
{
sockaddr_in sa;
int len = sizeof(sa);
socka.m_hSocket = accept(m_hSocket, (sockaddr *)&sa, (socklen_t *)&len);
if (socka.m_hSocket == INVALID_SOCKET)
return false;
if (pPort)
*pPort = htons(sa.sin_port);
if (sIP)
strcpy(sIP, inet_ntoa(sa.sin_addr));
}
else
socka.m_hSocket = accept(m_hSocket, nullptr, nullptr);
return socka.m_hSocket != INVALID_SOCKET;
}
bool Socket::Connect(const char *lpszHostAddress, unsigned int nHostPort)
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(nHostPort);
#ifdef _WIN32
sa.sin_addr.S_un.S_addr = inet_addr(lpszHostAddress);
#else
sa.sin_addr.s_addr = inet_addr(lpszHostAddress);
#endif // _WIN32
return !connect(m_hSocket, (sockaddr *)&sa, sizeof(sa));
}
bool Socket::GetPeerName(std::string &sIP, unsigned int &nPort)
{
sockaddr_in sa;
int len = sizeof(sa);
if (getpeername(m_hSocket, (sockaddr *)&sa, (socklen_t *)&len))
return false;
nPort = htons(sa.sin_port);
sIP = inet_ntoa(sa.sin_addr);
return true;
}
bool Socket::GetSockName(std::string &sIP, unsigned int &nPort)
{
sockaddr_in sa;
int len = sizeof(sa);
if (getsockname(m_hSocket, (sockaddr *)&sa, (socklen_t *)&len))
return false;
nPort = htons(sa.sin_port);
sIP = inet_ntoa(sa.sin_addr);
return true;
}
bool Socket::GetPeerName(char *sIP, unsigned int &nPort)
{
sockaddr_in sa;
int len = sizeof(sa);
if (getpeername(m_hSocket, (sockaddr *)&sa, (socklen_t *)&len))
return false;
nPort = htons(sa.sin_port);
if (sIP)
strcpy(sIP, inet_ntoa(sa.sin_addr));
return true;
}
bool Socket::GetSockName(char *sIP, unsigned int &nPort)
{
sockaddr_in sa;
int len = sizeof(sa);
if (getsockname(m_hSocket, (sockaddr *)&sa, (socklen_t *)&len))
return false;
nPort = htons(sa.sin_port);
if (sIP)
strcpy(sIP, inet_ntoa(sa.sin_addr));
return true;
}
int Socket::SendTo(const void *lpBuf, int nBufLen, unsigned int nHostPort, char *lpszHostAddress, int nFlags)
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(nHostPort);
#ifdef _WIN32
sa.sin_addr.S_un.S_addr = inet_addr(lpszHostAddress);
#else
sa.sin_addr.s_addr = inet_addr(lpszHostAddress);
#endif // _WIN32
return sendto(m_hSocket, (const char *)lpBuf, nBufLen, nFlags, (sockaddr *)&sa, (socklen_t)sizeof(sa));
}
int Socket::ReceiveFrom(void *lpBuf, int nBufLen, char *sIP, unsigned int *pPort, int nFlags)
{
sockaddr_in sa;
int len = sizeof(sa);
int n = recvfrom(m_hSocket, (char *)lpBuf, nBufLen, nFlags, (sockaddr *)&sa, (socklen_t *)&len);
if (n <= 0)
return n;
if (pPort)
*pPort = htons(sa.sin_port);
if (sIP)
strcpy(sIP, inet_ntoa(sa.sin_addr));
return n;
}
二、测试Demo
Service
#include <iostream>
#include "Socket.h"
using namespace std;
int main()
{
Socket Service;
Service.Create(8805);
Service.Listen();
Socket Recv;
Service.Accept(Recv);
char str[128]{ 0 };
string IP;
unsigned int Port;
while (true)
{
Recv.GetSockName(IP, Port);
cout << "\n" << IP.c_str() << " " << Port << endl;
Recv.GetPeerName(IP, Port);
cout << "\n" << IP.c_str() << " " << Port << endl;
Recv.Receive(str, sizeof(str));
cout << "\n" << str << endl;
}
return 0;
}
Client
#include "Socket.h"
#include <iostream>
using namespace std;
int main()
{
Socket client;
client.Create();
client.Connect("192.168.169.127", 8805);
string str;
while (true)
{
cin >> str;
client.Send(str.c_str(), str.length());
}
return 0;
}
三、测试结果
这上面的IP是我本地的IP,8805是Service的端口,56169是Client的端口。本来是想在虚拟机Linux下测试的,但是困了。
还有就是上面有一些强转的void*,这个封装是我在Linux下封装的,移到Windows上的vs2019时,它的一些方法就传char*类型的参数。
这个封装并不是很好,但是也是简化了一些操作吧。