C++封装TCP类,包括客户端和服务器

发布于:2024-06-19 ⋅ 阅读:(144) ⋅ 点赞:(0)

头文件 XTcp.h

#ifndef XTCP_H
#define XTCP_H

#ifdef WIN32
#ifdef XSOCKET_EXPORTS
#define XSOCKET_API __declspec(dllexport)
#else
#define XSOCKET_API __declspec(dllimport)
#endif
#else
#define XSOCKET_API
#endif

#include <string>
XSOCKET_API std::string GetIpByHost(std::string host);

//class XSOCKET_API XTcp
class XTcp
{
public:
	int CreateSocket();
	bool Bind(unsigned short port);
	XTcp Accept();
	void Close();
	int Recv(char *buf,int bufsize);
	int Send(const char *buf,int sendsize);
	bool Connect(const char *ip,unsigned short port,int timeoutms=1000);
	bool SetBlock(bool isblock);
	XTcp();
	virtual ~XTcp();
	int sock;
	unsigned short port;
	char ip[16];

};

#endif

源文件 XTcp.cpp

#include "XTcp.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define WIN32

#ifdef WIN32
#pragma comment(lib, "ws2_32.lib")
#include <windows.h>
#define socklen_t int
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define  closesocket close
#endif

//#include <thread>
using namespace std;
XSOCKET_API std::string GetIpByHost(std::string host)
{
	hostent *hptr = gethostbyname(host.c_str());
	if (!hptr)return "";
	in_addr addr;
	addr.s_addr = *(unsigned long *)hptr->h_addr;
	return inet_ntoa(addr);
}
XTcp::XTcp()
{
	sock = 0;
	port = 0;
#ifdef WIN32
	static bool first = true;
	if (first)
	{
		first = false;
		WSADATA ws;
		WSAStartup(MAKEWORD(2, 2), &ws);
	}
#endif
}
int XTcp::CreateSocket()
{
	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);
	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, 1000);
	return true;
}
int XTcp::Recv(char *buf, int bufsize)
{
	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);
	sock = 0;
}
XTcp XTcp::Accept()
{
	XTcp tcp;
	sockaddr_in caddr;
	socklen_t len = sizeof(caddr);
	int client = accept(sock, (sockaddr*)&caddr, &len);
	if (client <= 0) return tcp;
	//printf("accept client %d\n", client);
	printf(".");
	char *ip = inet_ntoa(caddr.sin_addr);
	strcpy(tcp.ip, ip);
	tcp.port = ntohs(caddr.sin_port);
	tcp.sock = client;
	//printf("client ip is %s,port is %d\n", tcp.ip, tcp.port);
	return tcp;
}

bool XTcp::Connect(const char *ip,unsigned short port,int timeoutms)
{
	if(sock <=0 ) CreateSocket();
	sockaddr_in saddr;
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = inet_addr(ip);
	SetBlock(false);
	fd_set set;
	if(connect(sock,(sockaddr*)&saddr,sizeof(saddr))!=0)
	{
		FD_ZERO(&set);
		FD_SET(sock,&set);
		timeval tm;
		tm.tv_sec = 0;
		tm.tv_usec = timeoutms*1000;
		if(select(sock+1,0,&set,0,&tm) <= 0)
		{
			printf("connect timeout or error!\n");
			printf("connect %s:%d failed!:%s\n",ip,port,strerror(errno));
			return false;
		}
	}
	SetBlock(true);
	printf("connect %s:%d success!\n",ip,port);
	return true;
}
XTcp::~XTcp()
{
}
bool XTcp::SetBlock(bool isblock)
{
	if(sock<=0) return false;
	#ifdef WIN32
		unsigned long ul = 0;
		if(!isblock) ul = 1;
		ioctlsocket(sock,FIONBIO,&ul);
	#else
		int flags = fcntl(sock,F_GETFL,0);
		if(flags<0)
			return false;
		if(isblock)
		{
			flags = flags&~O_NONBLOCK;
		}
		else
		{
			flags = flags|O_NONBLOCK;
		}
		if(fcntl(sock,F_SETFL,flags)!=0)
			return false;
	#endif
	return true;
}

服务器 server.cpp

#include <stdlib.h>
#include <windows.h>
#include "XTcp.h"
#include <string.h>
#include <iostream>


XTcp client;

DWORD WINAPI ThreadFunction(LPVOID lpParam) {
    // 线程要执行的代码
    char buf[1024] = {0};
	for (;;)
	{
		int recvlen = client.Recv(buf,sizeof(buf)-1);
		if (recvlen <= 0) break;
		buf[recvlen] = '\0';
				
		if (strstr(buf, "quit") != NULL)
		{
			char re[] = "quit success!\n";
			client.Send(re,strlen(re)+1);
			break;
		}
		int sendlen = client.Send("ok\n", 4);
		printf("recv %s\n",buf);
	}
	client.Close();
    return 0;
}

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(;;)
	{
		client = server.Accept();
		// 创建线程
		HANDLE hThread;
		DWORD dwThreadId;
		hThread = CreateThread(
			NULL, // 安全属性
			0,    // 初始堆栈大小
			ThreadFunction, // 线程函数
			NULL, // 线程函数的参数
			0,    // 创建标志
			&dwThreadId); // 线程ID的指针
	}
	server.Close();
	getchar();
	return 0;
}

客户端 client.cpp

#include "XTcp.h"
#include <iostream>
#include <Windows.h>

int main()
{
	for(;;)
	{
		XTcp client;
		client.CreateSocket();
		client.SetBlock(false);
		client.Connect("127.0.0.1",8080,3000);

		char msg[1024] = "hhhh";
		int len = strlen(msg);
		client.Send(msg, strlen(msg));

		char buf[1024] = { 0 };
		client.Recv(buf, sizeof(buf));
		printf("%s\n", buf);

		client.Close();

		Sleep(10);
	}

	getchar();
}

运行结果

服务器

在这里插入图片描述

客户端

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到