自制即时通信系统:socket网络编程(6)

本节介绍剩下的用例:个人信息修改用例、用户查询用例、客户信息传输用例、退出系统用例;
客户端中的个人信息修改用例步骤以及主要代码:
1)输入更改内容
2)本地格式校验
3)发送更改资料请求
4)返回反馈信息
5)更新用户资料命令

void CSetDlg::OnOK()
{
	// TODO: Add extra validation here
	UpdateData(TRUE);
	//发送修改个人信息到服务器
	cln_set set;
	set.magic=0x54;
	set.flags=0x04;
	sprintf(set.id,"%s",m_strId);
	sprintf(set.name,"%s",m_strName);
	sprintf(set.city,"%s",m_strCity);
	sprintf(set.info,"%s",m_strInfo);
	set.age=m_ByteAge;
	if(m_strSex=="男")
		set.sex=0x01;
	else
		if(m_strSex=="女")
			set.sex=0x02;
		else
			if(m_strSex=="其它")
			set.sex=0x04;
	extern CTCPSocket sock;
	char buf[888];
	memset(buf,'\0',sizeof(buf));
	int num;
	if((num=sock.rio_writeline(sock.sock, &set, sizeof(set), 0))<=0)
		::MessageBox(NULL,"发送请求失败","system error",MB_OK|MB_ICONERROR);
	//接受响应
	int size=sock.rio_readlineb(sock.rio, buf, sizeof(buf));
	if(size>0)
	{
		header *serv =(header *)buf;
		if((serv->magic==0x55) && (serv->flags==0x04))
		{
			::MessageBox(NULL,"修改成功","system error",MB_OK|MB_ICONERROR);
			//修改成功则更改本地好友列表
			FriendMsg p;
			p.name=m_strName;
			p.sex=m_strSex;
			p.age=m_ByteAge;
			p.city=m_strCity;
			p.info=m_strInfo;
			CWnd *pWnd=GetParent();
			((CIMPropertySheet *)pWnd)->page1->listmsg(&p);
			//刷新好友列表的自己
			//待写
			//更新LastMsg
			LastMsg.name=m_strName;
			LastMsg.sex=m_strSex;
			LastMsg.age=m_ByteAge;
			LastMsg.city=m_strCity;
			LastMsg.info=m_strInfo;
		}
		else
			if((serv->magic==0x54) && (serv->flags==0x04))
				::MessageBox(NULL,"修改失败","system error",MB_OK|MB_ICONERROR);
			else
				::MessageBox(NULL,"数据包不在服务范围内","system error",MB_OK|MB_ICONERROR);
	}
	//CPropertyPage::OnOK();
}

void CSetDlg::reset()
{
	m_strName=LastMsg.name;
	m_strSex=LastMsg.sex;
	m_ByteAge=LastMsg.age;
	m_strCity=LastMsg.city;
	m_strInfo=LastMsg.info;
	UpdateData(FALSE);
}

void CSetDlg::OnReset()
{
	// 重置
	reset();
}

--------------------------------------------------------------------------------------------------------------

客户端中的用户查询用例步骤以及主要代码:
1)按ID/昵称查找,在线查找,查找全部
2)发送查询好友请求
3)客户端返回查询结果
4)客户端显示查询结果

void CAddDlg::OnButtonQueryall() 
{
	// TODO: 查询所有好友信息
	cln_query query;
	memset(&query,'\0',sizeof(query));
	query.magic=0x54;
	query.flags=0x08;
	extern CTCPSocket sock;
	memset(servbuf,'\0',sizeof(servbuf));
	int num;
	if((num=sock.rio_writeline(sock.sock, &query, sizeof(query), 0))<=0)
		::MessageBox(NULL,"发送请求失败","system error",MB_OK|MB_ICONERROR);
	//接受响应
	int size=sock.rio_readlineb(sock.rio, servbuf, sizeof(servbuf));
	if(size>0)
	{
		serv_query *serv_answer=(serv_query *)servbuf;
		if((serv_answer->magic==0x55) && (serv_answer->flags==0x08))
		//查询成功,插入查询列表
		{
			DelAllData();//删除之前查询结果
			if(serv_answer->friend_num==0)
				::MessageBox(NULL,"查询结果为空","system error",MB_OK|MB_ICONERROR);
			else
			{
				for(int i=0; i<serv_answer->friend_num;)
				{
					AddItem(serv_answer, i);
					 i++;
				}
			}
		}
		else
			if((serv_answer->magic==0x54) && (serv_answer->flags==0x08))
				::MessageBox(NULL,"查询失败","system error",MB_OK|MB_ICONERROR);
			else
				::MessageBox(NULL,"数据包不在服务范围内","system error",MB_OK|MB_ICONERROR);
	}
}

--------------------------------------------------------------------------------------------------------------

客户端中的即时信息传输用例步骤以及主要代码:
1)选择发送内容
2)获取发送方地址,端口,不在线则做离线处理
3)传输信息
5)对方显示信息或在服务器中插入离线信息

unsigned int WINAPI CIMDlg::RecvFromThreadFunc(void *vargp)//循环接收UDP消息线程
{
	CIMDlg * obj=(CIMDlg *)vargp;
	for(;;)
	{
		struct sockaddr_in clntAddr;
		int clntAddrLen= sizeof(clntAddr);
		if(UDPRecvFlags==0)
		{
			int numBytsRcvd = recvfrom(UDPServ, UDPRecvBuf, 113, 0 , (struct sockaddr *)&clntAddr, &clntAddrLen);
			if(numBytsRcvd < 0)
				continue;
			else
			{
				UDPRecvFlags=1;
				obj->UDPServThreadFunc();
			}
		}
	}
	return 1;
}

void CIMDlg::UDPServThreadFunc()
{
	if(UDPRecvFlags==1 || UDPOfflineMsgFlags==1)
		SendMessage(newfriendmsg);//发现有好友消息传来,向主线程发送消息进行通知
}

unsigned int WINAPI CIMDlg::UDPClientThreadFunc(CChat * chat)//发送好友消息函数
{
	if(strcmp(chat->SelfMsg.state,"在线")==0)
	{
		int size=strlen(chat->m_strChat);
		if(size==0)
			return 0;
		//暂时不足点,发送数据空间可压缩
		UDP_Package *pack=new UDP_Package;
		sprintf(pack->id,"%s",chat->SelfMsg.selfid);
		sprintf(pack->message,"%s",chat->m_strChat);

		UDPClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//必须在此处建立套接字,在init()中不行
		if(UDPClient<0)
			printf("socket() failed\n");
		
	//聊天窗口点击发送时调用此函数,将聊天信息发送给好友
		struct sockaddr_in servAddr;
		int servAddrLen=sizeof(servAddr);
		memset(&servAddr, 0, sizeof(servAddr));
		servAddr.sin_family = AF_INET;
		servAddr.sin_addr.s_addr=htonl(chat->SelfMsg.ip);
		servAddr.sin_port=htons(chat->SelfMsg.port);
		
		//sprintf(buf,"%s",pack);
		int numBytsRcvd = sendto(UDPClient, (char *)pack, 112, 0 , (struct sockaddr *)&servAddr, servAddrLen);
		if(numBytsRcvd < 0)
		{
			::MessageBox(NULL,"发送消息失败","system error",MB_OK|MB_ICONERROR);
			return 0;
		}
		else//发送成功则将消息显示在聊天窗口中
		{
		//	EnterCriticalSection(&g_cs);// 进入临界区

			chat->GetDlgItemText(IDC_EDITOLDMSG,chat->strShow);
			chat->strShow+=chat->SelfMsg.selfname;
			chat->strShow+=":";
			chat->strShow+="\r\n";
			chat->strShow+=chat->m_strChat;
			chat->strShow+="\r\n";

			chat->SetDlgItemText(IDC_EDITOLDMSG, chat->strShow);
			chat->m_strChat="";
		//	LeaveCriticalSection(&g_cs); // 离开临界区
		}
		closesocket(UDPClient);
		delete pack;
	}//好友在线信息处理完毕
	else
	{	//此处添加好友不在线时信息发送处理
		extern CTCPSocket sock;
		cln_offline_msg offline;
		memset(&offline,'\0',sizeof(offline));
		offline.magic=0x54;
		offline.flags=-128;
		sprintf(offline.resid,"%s",chat->SelfMsg.selfid);
		sprintf(offline.desid,"%s",chat->SelfMsg.userid);
		sprintf(offline.message,"%s",chat->m_strChat);
		int num;
		if((num=sock.rio_writeline(sock.sock, &offline, sizeof(offline), 0))<=0)
			::MessageBox(NULL,"rio_writen() failed","system error",MB_OK|MB_ICONERROR);

		//将消息显示到记录框
		chat->GetDlgItemText(IDC_EDITOLDMSG,chat->strShow);
		chat->strShow+=chat->SelfMsg.selfname;
		chat->strShow+=":";
		chat->strShow+="\r\n";
		chat->strShow+=chat->m_strChat;
		chat->strShow+="\r\n";

		chat->SetDlgItemText(IDC_EDITOLDMSG, chat->strShow);
		chat->m_strChat="";
	}
	return 1;	
}

--------------------------------------------------------------------------------------------------------------

客户端中的退出系统用例步骤以及主要代码:
1)发送退出消息
2)接收服务器反馈消息并正常下线

BOOL CIMPropertySheet::DestroyWindow() 
{
	// TODO: 下线通知
	//关闭TCP套接字
	cln_offline offline;
	offline.magic=0x54;
	offline.flags=0x20;
	FriendMsg * p=(FriendMsg*)this->page1->m_TreeCtl.GetItemData(this->page1->SelfItem);
	sprintf(offline.userid,"%s",p->userid);
	extern CTCPSocket sock;
	char buf[88];
	memset(buf,'\0',sizeof(buf));
	int num;
	if((num=sock.rio_writeline(sock.sock, &offline, sizeof(offline), 0))<=0)
		::MessageBox(NULL,"下线请求失败","system error",MB_OK|MB_ICONERROR);
	closesocket(sock);
	return CPropertySheet::DestroyWindow();
}

--------------------------------------------------------------------------------------------------------------

其余还有一些用例函数没有列出,例如添加,删除好友,在线上报线程用例等等,这些功能不难,再贴代码就显得更累赘了。

 

你可能感兴趣的:(windows,网络编程,VC,即时通信,Sockets)