这里提供了两个C/C++中服务器与客户端之间通讯的两个程序,程序中封装了通信之间的函数方法,我们以这个程序为例进行封装。
文件目录结构按照C/C++标准开源项目进行存放:
├─bin
├─doc
├─lib
└─src
├─xsocket
│ │ XTCP.h
│ │ XTCP.cpp
XTCP.h
#ifndef XTCP_H //保证只初始化一次
#define XTCP_H
#ifdef WIN32
#pragma once
#ifdef XSOCKET_EXPORTS
#define XSOCKET_API __declspec(dllexport)
#else
#define XSOCKET_API __declspec(dllimport)
#endif
#else
#define XSOCKET_API
#endif // WIN32
#include
class XSOCKET_API XTCP
{
public:
int createSocket();
bool bindListen(unsigned short port);
void closeSocket();
int receiveData(char* buf,int bufsize);
int sendData(const char* buf, int sendsize);
bool connectSocket(const char* ip, unsigned short port);
XTCP acceptClient();
XTCP();
virtual ~XTCP();
int sock = 0;
unsigned short port = 0;
char ip[16];
};
#endif // !XTCP_H
XTCP.cpp
#include "XTCP.h"
#ifdef WIN32
#include
#define socklen_t int
#else
#include
#include
#include
#include
//函数名替换,重定义,将close关闭sock的函数转化为closesocket
#define closesocket close
#define strcpy_s strcpy
#endif
#include
#include
#include
XTCP::XTCP() {
#ifdef WIN32
static bool is_first = true;
if (is_first) {
is_first = false;
//通过进程启动Winsock DLL使用
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
}
#endif
}
bool XTCP::connectSocket(const char* ip, unsigned short port) {
if (sock <= 0) {
createSocket();
}
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
//将字符串ip地址转化为网络地址
saddr.sin_addr.s_addr = inet_addr(ip);
if (connect(sock, (const sockaddr*)&saddr, sizeof(saddr)) != 0) {
// strerror(errno)将错误转化为字符串
std::cout << "connect " << ip << " : " << port << " failed! ";
return false;
}
std::cout << "connect " << ip << " : " << port << " success!\n ";
return true;
}
int XTCP::createSocket() {
//创建socket,创建失败返回-1,AF_INET表示ipv4协议,SOCK_STREAM表示接受tcp/ip协议的数据
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
std::cout << "create socket failed" << std::endl;
}
return sock;
}
bool XTCP::bindListen(unsigned short port) {
if (sock <= 0) {
createSocket();
}
//绑定地址
sockaddr_in saddr;
saddr.sin_family = AF_INET;
//大端字节序和小端字节序的问题,
saddr.sin_port = htons(port);
//0设置为绑定本机地址
saddr.sin_addr.s_addr = htonl(0);
//绑定地址
if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) {
std::cout << "bind port " << port << " failed.\n";
return false;
}
std::cout << "bind port " << port << " successful.\n";
//监听客户端发送的信息
//backlog=10表示缓冲大小
listen(sock, 10);
return true;
}
XTCP XTCP::acceptClient() {
XTCP tcp;
//每个连接就会生成一个client
sockaddr_in caddr;
socklen_t len = sizeof(caddr);
//在accept之前会进行三次握手(由操作系统完成),accept只是获取了握手后的信息
int client_sock = accept(sock, (sockaddr*)&caddr, &len);
if (client_sock <= 0) {
return tcp;
}
tcp.sock = client_sock;
std::cout << "accept client " << client_sock << ".\n";
char* ip = inet_ntoa(caddr.sin_addr);
strcpy_s(tcp.ip, ip);
tcp.port = ntohs(caddr.sin_port);
std::cout << "client ip address " << tcp.ip << ".\n";
std::cout << "client port " << tcp.port << ".\n";
return tcp;
}
int XTCP::receiveData(char* buf, int bufsize) {
return recv(sock, buf, bufsize, 0);
}
int XTCP::sendData(const char* buf, int sendsize) {
//需要全部发送完全才能结束
int sendedSize = 0;
while (sendedSize!=sendsize) {
int len = send(sock, buf + sendedSize, sendsize - sendedSize, 0);
if (len <= 0) {
break;
}
sendedSize += len;
}
return sendedSize;
}
void XTCP::closeSocket() {
if (sock <= 0) {
return;
}
closesocket(sock);
}
XTCP::~XTCP() {
}
首先编写编写makefile
文件,用于编译两个程序,可以按照以下命令进行编译,编译后将会在同级目录下生成一个libxsokcet.so
文件,理论上这个时候Linux封装就完成了。
libxsocket.so:XTCP.cpp XTCP.h
g++ $+ -o $@ -fpic -shared -std=c++11
但是在实际过程中,常常会出现一个.so
文件不存在/找不到的问题。我们在这里编写一个测试程序,项目创建在和xsocket
的同级目录,测试libxsocket.so
是否可以调用。
testTCP.cpp
#include
#include"XTCP.h"
int main()
{
XTCP client;
client.connectSocket("192.168.245.129", 8080);
return 0;
}
我们通过以下程序编译这个程序之后:
testTCP:testTCP.cpp
g++ $+ -o $@ -I../xsocket -std=c++11 -lpthread -lxsocket -L../xsocket
可以发现,尽管我们在编译过程中设置了libxsocket.so
的路径所在位置,但是在运行之后还是会存在找不到文件,报错内容如下error while loading shared libraries: libxsocket.so: cannot open shared object file: No such file or directory
,所以在运行的时候需要重新编写一个脚本,来执行testTCP
,并且显示指定libxsocket.so
的路径所在位置,脚本如下所示:
export LD_LIBRARY_PATH=../xsocket
./testTCP
这样testTCP
就执行成功了。
Windows封装.lib
文件,我们借助vs studio 2019编译器完成编译,还是以上述两个文件和文件结构为例:
首先在xsocket
的同级目录创建一个项目(选择具有导出项的(DLL)动态链接库,千万不要选错了),项目名自取。
项目创建后将会自动生成一些配置文件,如下图所示
然后将XTCP.h
和XTCP.cpp
文件添加到目前这个新建的项目中来,文件结构如上图所示,具体简体方法,
XTCP.h
和XTCP.cpp
文件添加到当前项目目录。XTCP.h
文件。XTCP.cpp
文件和XTCP.h
文件添加方法一致。修改工作目录
中间可能会有一个弹窗显示错误,可以忽略,只要编译显示没有失败/错误就行。
验证是否可以使用,在项目目录新建一个项目,用于验证该dll
是否可以使用:
在新建项目的 解决方案上右键,选择添加现有项目,将刚才打包的项目添加进行,选择.vcxproj
文件。
然后再右键 解决方案 ,设置启动项目和项目依赖项,
按照下图设置,设置新建项目为主项目,依赖项目为打包项目。
然后再设置当前项目的动态链接库位置,选择当前项目,右键,选择属性,如下图所示:
然后再在当前项目新建一个cpp文件运行以下程序,
#include
#include"XTCP.h"
int main()
{
XTCP client;
client.connectSocket("192.168.245.129", 8080);
return 0;
}
如果不报错则,动态链接库封装成功。