(C/S)线程函数是否应该放入C++类中?

    在写一个C/S的客户端时,想要把收和发分开处理,于是很自然的想到了要用到线程。

    在用C语言写的时候代码可以调试出来,因为是结构化程序设计,所以函数与函数之间耦合性不是很强,线程函数也就没有与其他函数起冲突。但是当我想要把代码改为C++实现时,出现问题了。

    把函数封装在类里,写成成员函数的形式,体现内聚性。我们写的代码应该尽量的高内聚、低耦合

    一旦使用类,所有函数都封装作为类的成员函数,那么,创建线程时,必然会创建新的对象。接着执行新的对象的构造函数,执行线程函数,递归,程序会崩溃。。也尝试把线程函数写为类的友元函数 (类中函数声明前加friend),可是创建线程的函数 pthread_create() 的参数依然是个问题,如果传入套接字,那么谁来接收?如果是这个类的另一个对象接收,势必会执行默认的拷贝构造函数。所以还是会出现上述问题。

    当然,如果形参写的是引用的话,不会多拷贝一份实参,这个方法我还没有尝试。

    想到的另一种方式是,建立两个类。一个用于接收,另一个用于发送。此外,把线程函数的声明放在两个类的外面。

当发送类与服务器建立连接时,执行线程函数,在线程函数中创建接收类的对象。把发送类与服务器建立的套接字,作为线程函数的参数传递进去。接着,线程函数中,此参数作为结束类的构造函数参数传入。在结束类中就可以实现与服务器的通信。同时,实现了发送与结束的分离,即实现多线程。

    下面是部分代码,供以参考:

//构造函数,实现初始化的操作
TellerSend::TellerSend()    
{
	sfd = -1;
	tcpConnect("127.0.0.1", 9999);	
	if (-1 == sfd)
	{
		return;
	}	
	cout << "connnect to server success!" << endl;
	
	//开线程(只用于接收服务器的应答消息)
	int ret = -1;
	int newfd = this->sfd;        //将此套接字作为线程参数传递
	pthread_t rcvThread;
	ret = pthread_create(&rcvThread, NULL, handleRcv, (void *)newfd);
	if (-1 == ret)
	{
		printf("子线程退出!\n");
		newfd = -1;
	}
	
	handleSnd();            //向服务器发送请求(主线程)
}

    接着是线程函数:

//接收服务器的应答消息
void *handleRcv(void *arg)                  
{
	//创建新类的对象,参数为已经与服务器建立连接的套接字
	int newsfd = (int)arg;	
	TellerRecv trecv(newsfd);
	
	return 0;
}

    然后是接收类的构造函数:

//构造函数,只用于接收(根据接收的包头信息的不同,执行相应的成员函数)
TellerRecv::TellerRecv(int newsfd = -1)
{
	this->sfd = newsfd;
	cout << "this->sfd = " << newsfd << endl;
	
	int ret = -1;	
	QueryHead qhead;	
	while (1)
	{
	    //此套接字sfd 是新类的私有成员
		ret = recv(sfd, (char *)&qhead, sizeof(qhead), 0);
		if (-1 == ret)
		{
			close(sfd);
			exit(-1);
		}
		
		//根据接收到的包头中的命令,接收之后不同的包体
		switch ( qhead.cmd )
		{
			case 0:
			{
				close(sfd);
				exit(0);
			}break;
			
			case 1:          
			{
				//....
			}break;
			
			//...
			
			default:
			    break;
		}
	}
}

    最后给出头文件中类的声明:

//发送类
class TellerSend
{
public:
	TellerSend();             //构造函数,实现初始化的操作
	~TellerSend(){};         	
	
	void tcpConnect(const char *ip, const int port);             //连接服务器
	void handleSnd();
	int  getCommand();             //菜单项
	void LoginSnd();               //柜员注册
	void LandSnd();                //柜员登陆	
	void QuitSnd();                //客户端退出
protected:
	
private:
	int sfd;            //连接服务器的套接字
	int cmd;            //接收菜单项输入(命令)
};

//接收类
class TellerRecv
{
public:
	TellerRecv(int sfd);           //构造函数的参数通过线程参数传递(实际上是前一个类的私有成员)
	~TellerRecv(){};
	
	void LoginRcv();
	void QuitRcv();
	void LandRcv();
protected:

private:
	int sfd;
	int cmd;
};

extern int LandFlag;       //登陆成功标志
extern void *handleRcv(void *arg);  //线程函数(在此线程函数中创建新的对象)

extern void LoginInput(RequestLogin &arg); //注册信息录入

#endif
     如果读者有更好的方式处理线程和类的问题,欢迎指正。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值