对socket通信的封装以及实现服务端的多进程服务

本文档展示了使用C++实现的TCP服务器和客户端通信程序,服务器采用多进程并发处理客户端连接,通信过程包括封装socket操作类,隐藏底层细节,支持发送和接收数据。客户端向服务器发送报文并接收回复。程序结构清晰,易于理解。
摘要由CSDN通过智能技术生成


前言

本篇内容是对已实现的通信程序进行模块化封装以及将服务端改为多进程并发通信,将初始化sokcet和recv与send操作封装成类,套接字描述符与通信实现的具体细节对用户隐藏。
实现方法参照 https://www.freecplus.net/44e059cca66042f0a1286eb188c51480.html


通信服务端

服务端main主函数

/*
 * 此程序演示socket通信服务
 * 作者:zhy 时间:2020 4 4
 */
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>

// 声明服务端socket通信操作类
CTcpServer TcpServer;

void EXIT(int sig);

int main()
{
	//忽略全部信号
	for (int ii = 0;ii < 50;++ii) signal(ii,SIG_IGN);

	//设置SIGINT和SIGTERM的信号处理函数
	signal(SIGINT,EXIT); signal(SIGTERM,EXIT);

	// 初始化服务端,设置监听端口
	if (TcpServer.InitServer(5000) == false)
	{ printf("服务端初始化失败,程序退出。\n"); return -1; }
	
	while(1)
	{
		if ( TcpServer.Accept() == false) continue;
		// 父进程关闭用于通信的socket(对子进程无影响)回到循环开始继续监听连接
		if (fork() > 0) { TcpServer.CloseClient(); continue; }
		// 子进程关闭用于监听连接的socket,只与客户端通信
		TcpServer.CloseListen();

		printf("客户已连接。\n"); 
		

	    //与客户端通信,接受到客户端发送的报文后,回复ok
    	char buffer[1024];
		unsigned int  a;

    	while(1)
    	{
	    	memset(buffer,0,sizeof(buffer));
	    	if(TcpServer.Recv(&a,sizeof(long)) <= 0) break;
	    	printf("接收:%d\n",ntohl(a));
    
    		strcpy(buffer,"ok");
    		if(TcpServer.Send(buffer,sizeof(buffer)) <= 0) break;
    		printf("发送:%s\n",buffer);
    	}

    	printf("客户已断开连接。\n");

		return 0;	//子进程退出
	}
}
    
//SIGINT和SIGTERM信号处理函数
void EXIT(int sig)
{
	printf("\n程序退出sig=%d\n",sig);

    TcpServer.~CTcpServer();	//手动调用析构函数,释放资源

	exit(0);
}

服务端操作类

class  CTcpServer
{
public:
	int m_listenfd;		// 服务端用于监听的socket
	int m_clientfd;		// 客户端连上来的socket

	CTcpServer();

	bool InitServer(const int port);	//初始化服务端

	bool Accept();		//等待客户端的连接

	//向对端发送报文
    int Send(const void *buf,const int buflen);
    //接收对端的报文
    int Recv(void *buf,const int buflen);

	void CloseClient();	//关闭客户端的socket

	void CloseListen();	//关闭用于监听的socket

   ~CTcpServer();
};

CTcpServer::CTcpServer()
{
	m_listenfd = 0;
	m_clientfd = 0;
}

CTcpServer::~CTcpServer()
{
	if(m_listenfd != 0) close(m_listenfd);
	if(m_clientfd != 0) close(m_clientfd);
}

bool CTcpServer::InitServer(const int port)	//初始化服务端
{
	
    m_listenfd = socket(AF_INET,SOCK_STREAM,0);       // 创建服务端用于监听的socket

    //把服务端用于通信的地址和端口绑定到socket上
    struct sockaddr_in servaddr;        // 服务器地址信息的数据结构
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;      // 协议族,在socket编程中只能是AF_INET
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   // 本主机的任意IP地址
    //servaddr.sin_addr.s_addr = inet_addr("192.168.1.12"); // 绑定指定的地址
    servaddr.sin_port = htons(port);    // 绑定通信端口(数值可改)
    if (bind(m_listenfd ,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
    { close(m_listenfd); m_listenfd = 0; return false; }

    //把socket设置为监听模式
    if (listen(m_listenfd,5) != 0 ) { close(m_listenfd); m_listenfd = 0; return false; }

	return true;
}

bool CTcpServer::Accept()		//等待客户端的连接
{
	if ((m_clientfd=accept(m_listenfd,0,0)) <= 0) return false;

	return true;
}

//向对端发送报文
int CTcpServer::Send(const void *buf,const int buflen)
{
    return send(m_clientfd,buf,buflen,0);
}

//接收对端的报文
int CTcpServer::Recv(void *buf,const int buflen)
{
    memset(buf,0,buflen);
    return recv(m_clientfd,buf,buflen,0);
}

void CTcpServer::CloseClient()	//关闭客户端的socket
{
	if(m_clientfd!=0) { close(m_clientfd); m_clientfd=0;}
}

void CTcpServer::CloseListen()	//关闭用以监听的socket
{
	if(m_listenfd!=0) { close(m_listenfd); m_listenfd=0;}
}

通信客户端

客户端main函数

/*
 * 此程序演示socket通讯客户端
 * 作者:zhy 时间:2020 4 4
 */
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{
	CTcpClient TcpClient;

	//向服务器发起连接请求
	if (TcpClient.ConnectToServer("192.168.150.142",5000) == false)
	{ printf("连接服务器失败,程序退出。\n"); return -1; }


	char strbuffer[1024];
	unsigned int a = 14664464;
	unsigned int b = htonl(a);
	unsigned int c = ntohl(b);

	printf("a = %ld\nb = %ld\nc = %ld\n",a,b,c);
	//与服务端通讯,发送一个报文后等待回复,然后再发下一个报文
	for (int ii =0;ii<30;ii++)
	{
		/*
		memset(strbuffer,0,sizeof(strbuffer));
		sprintf(strbuffer,"这是第%d个报文",ii);
		*/
		if (TcpClient.Send(&b,sizeof(long)) <= 0) break;
		printf("发送:%d\n",b);

		if (TcpClient.Recv(strbuffer,sizeof(strbuffer)) <= 0) break;
		printf("接收:%s\n",strbuffer);
    	sleep(1);
	}
}

客户端操作类

class CTcpClient
{
private:

	int m_sockfp;

public:

	CTcpClient();
	
    //向服务器发起连接,Serverip-服务端ip ,port通讯端口
	bool ConnectToServer(const char* Serverip,const int port);
	//向对端发送报文
	int Send(const void *buf,const int buflen);
	//接收对端的报文
	int Recv(void *buf,const int buflen);

   ~CTcpClient();

//向服务器发起连接,Serverip-服务端ip ,port通讯端口
bool CTcpClient::ConnectToServer(const char* Serverip,const int port)
{
    m_sockfp = socket(AF_INET,SOCK_STREAM,0);     // 创建客户端的socket

    struct hostent* h;  //IP地址信息的数据结构
    if ( (h = gethostbyname(Serverip)) == 0 )
    { close(m_sockfp); m_sockfp = 0; return false; }

    //把服务器的地址和端口转换为数据结构
    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(port);
    memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);

    //向服务器发起连接请求
    if ( connect(m_sockfp,(struct sockaddr*)&servaddr,sizeof(servaddr)) != 0 )
	{ close(m_sockfp); m_sockfp = 0; return false; }

	return true;
}

//向对端发送报文
int CTcpClient::Send(const void *buf,const int buflen)
{
	return send(m_sockfp,buf,buflen,0);
}

//接收对端的报文
int CTcpClient::Recv(void *buf,const int buflen)
{
	memset(buf,0,buflen);
    return recv(m_sockfp,buf,buflen,0);
}

CTcpClient::CTcpClient()
{
	m_sockfp = 0;
}

CTcpClient::~CTcpClient()
{
	if (m_sockfp != 0) close(m_sockfp);
}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值