C++socket编程(四):4.2 创建XTcp动态链接库项目

C++socket编程(四):4.2 创建XTcp动态链接库项目,第1张

C++socket编程(四):4.2 创建XTcp动态链接库项目

前言:
在完成了TCP的服务端Demo之后,现在开始尝试开发客户端方面的项目。在做客户端之前先想下,客户端和服务端是不是公用一些类,头文件,创建socket,关闭socket,recv,send。这些客户端和服务端应该是公用的。应该放在XTcp.h,XTcp.cpp中。如果我们直接把这些文件加入到我们的项目中,这个方案非常不灵活,每次编译项目的时候,都要加一大推文件。还要重新编译这部分代码。如果解决这个问题呢?这里提出一个动态库的概念。

本博客重点将linux下将服务器的建立绑定连接socket功能接口的过程。
如下代码:
创建so的makefile

libxsocket.so:XTcp.h XTcp.cpp
        g++ $+ -o $@ -fpic -shared -std=c++11

编译生成动态链接库的生成文件XTcp.cpp

#include "XTcp.h"
#ifdef WIN32
#include 
#define socklen_t int
#else
#include 
#include 
#include 
#include 
#define closesocket close
#endif
#include 
#include 
#include 
#include 

using namespace std;

XTcp::XTcp()
{
#ifdef WIN32
	static bool first = true;
	if (first)
	{
		first = false;    //保证只进入一次
		WSADATA ws;
		WSAStartup(MAKEWORd(2, 2), &ws); //相当于加载了动态库,给引用增加1,这个只需要调用以此,但是需要调用在最前面
	}

#endif
}

int XTcp::CreateSocket()    //第一步创建socket
{
	sock = socket(AF_INET, SOCK_STREAM, 0);

	if (sock == -1)
	{
		printf("create socket failed!n");
	}
	return sock;
}

bool XTcp::Bind(unsigned short port)
{
	if (sock <= 0)
		CreateSocket();
	//创建
	sockaddr_in saddr;
	saddr.sin_family = AF_INET;   //协议
	saddr.sin_port = htons(port); //本地字节序转换为网络字节序
	saddr.sin_addr.s_addr = htonl(0);   //任意ip地址发过来的数据都接收

	//绑定
	//用bind绑定,绑定哪一个端口
	if (::bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)
	{
		printf("bind port %d failed!n", port);
		return false;
	}

	printf("bind port %d success!n", port);

	listen(sock, 10);    //这个函数已经调用,就会告诉系统,这个socket可以通过这
								//个端口来跟它进行接收连接了
								//但是,连接的信息还会用到另外一个函数。10指的是在我这次获取连接信息的时候
								//最大支持多少个连接信息
	return true;
}

int XTcp::Recv(char* buf, int bufsize)
{
	//Revc考虑一点,有时候需要接收指定大小,接收不到指定大小,就会失败
	return recv(sock, buf, bufsize, 0);
}

int XTcp::Send(const char* buf, int size)
{
	int s = 0;
	while(s!=size)   //一直发送,直到发送完毕
	{
		int len = send(sock, buf + s, size - s, 0);
		if (len <= 0)
			break;
		s += len;
	}
	return s;
}

void XTcp::Close()
{
	if (sock <= 0)
		return;
	closesocket(sock);
}

XTcp XTcp::Accept()
{
	XTcp tcp;
	sockaddr_in caddr;

	socklen_t len = sizeof(caddr);

	int client = accept(sock, (sockaddr*)&caddr, &len);//创建一个新的socket,用来与客户端单独进行通信
	if (client <= 0)
		return tcp;        //如何让外部知道我accept是成功还是失败,可以通过这个返回对象的默认socket来判断
	printf("accept client %dn", client);
	tcp.ip = inet_ntoa(caddr.sin_addr);
	tcp.port = ntohs(caddr.sin_port);       //将网络字节序转化为本地字节序
	tcp.sock = client;
	printf("client ip is %s,port is %dn", tcp.ip.c_str(), tcp.port);
	return tcp;
}

XTcp::~XTcp()
{

}

XTcp.h

//#pragma once
#ifndef _XTCP_H_
#define _XTPC_H_
#include 
class XTcp
{
public:
	int CreateSocket();
	bool Bind(unsigned short port);
	XTcp Accept();   //注意这个返回类型不是指针类型,我们需要在后面重新调用一个closesocket函数
	void Close();
	int Recv(char *buf,int bufsize);
	int Send(const char *buf,int sendsize);
	XTcp();
	virtual ~XTcp();
	int sock = 0;
	unsigned short port = 0;
	std::string ip;    //这些信息可以对外开放
};

#endif //_XTCH_H_

如上面的内容。我们完成了动态库的生成,下面需要进行动态库的调用
如下服务器代码:server.cpp

#include 
#include 
#include 
#include"XTcp.h"

class TcpThread
{
public:
	void Main()
	{
		char buffer[1024] = { 0 };

		for (;;)
		{
			int recvlen = client.Recv(buffer, sizeof(buffer) - 1);

			if (recvlen <= 0)
				break;

			buffer[recvlen] = '';

			if (strstr(buffer, "quit") != NULL)
			{
				char re[] = "quit success!n";
				client.Send(re, strlen(re) + 1);
				break;
			}

			int sendlen = client.Send("okn", 4);
			printf("recv %sn", buffer);
		}

		client.Close();
		delete this;
	}
	XTcp client;
};

int main(int argc, char* argv[])
{
	unsigned short port = 8080;

	if (argc > 1)
	{
		port = atoi(argv[1]);
	}

	XTcp server;

	server.CreateSocket();
	server.Bind(port);


	for (;;)
	{
		XTcp client = server.Accept();
		TcpThread* th = new TcpThread;               //需要考虑什么时候清理这个线程对象
		th->client = client;
		std::thread sth(&TcpThread::Main, th);               //第二个参数是对象,第一个参数是对象的方法

		sth.detach();                                                //表示释放主线程拥有的子线程的资源

	}    //来支持多个客户端

	server.Close();
	getchar();
	return 0;
}

看下面的编译与链接xsocket动态库的makefile

tcpserver:server.cpp
        g++ $+ -o $@ -I../xsocket/xsocket -std=c++11 -lpthread -lxsocket -L../xsocket/xsocket

这样就完成了linux下动态库的生成与调用,但是还有一个问题,我们生成的动态库需要配置下环境变量之后,我们才能正常调用这个动态库.
可看如下代码,提供了一种解决方法

export LD_LIBRARY_PATH=../xsocket/xsocket
./tcpserver

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5698343.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存