学习笔记之网络软件设计(二)

任务二 简单的聊天程序

一、要求

1.编写两对简单的一对一聊天程序,分别为面向连接方式和无连接方式(我选用无连接方式)
2.当开始通信后,一方先从键盘获得用户字符串,发送到另一方,然后等待对方数据,显示,再循环这个过程
3.而另一方则是先等待对方字符串,显示;然后从键盘获得用户字符串,发送,再循环这个过程。

进阶要求

双方可以自由聊天,即随时都可以输入或显示对方的数据
软件具有图形化界面

二、与任务相关的实验

05-套接字接口函数
07-隐式绑定
11-多路复用
12-阻塞与非阻塞
13-并发服务

三、完成过程

1、服务器端

这个任务我采用的无连接的方式完成。
通信的基本步骤:
1.服务器开启,申请套接字,确定本地端点,默认4660。
2.开启的时候,额外开启一个线程,用于接收来自客户端的消息,并显示在聊天记录中。
3.点击发送按钮,可以将发送消息框中的消息发送出去,并显示在聊天记录中。

以下为部分代码( 东拼乱凑的感觉,希望大神指导~~
//定义的部分变量
SOCKET s;
sockaddr_in local;
sockaddr_in remote;

int len;
CString sendbuf;
char recvbuf[128];
WSAData wsa;

CString buffer;		//存放一次的消息
static CString save;	//存放聊天记录

//点击启动按钮后的执行代码
void CTanc_mfc_chat_serverDlg::OnRunbutton() 
{

	WSAStartup(0x101,&wsa);
	s = socket(AF_INET,SOCK_DGRAM,0);	//申请套接字
	
	local.sin_family = AF_INET;
	local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);		//0.0.0.0
	local.sin_port = htons(0x1234);		//port 4660

	bind(s,(sockaddr*)&local,sizeof(local));

	//创建服务线程
	CreateThread(NULL, 0 ,ThreadServer, NULL, 0, NULL);

	AfxMessageBox("服务器已启动");
}

//线程部分的代码,用于接收消息 并显示在聊天记录中
DWORD WINAPI ThreadServer(LPVOID lpParameter)
{
	while(TRUE)
	{
		len = sizeof(remote);
		recvfrom(s,recvbuf,sizeof(recvbuf),0,(sockaddr*)&remote,&len);
		buffer.Format(_T("客户说 :%s\r\n"),recvbuf);
		save = save + buffer;
		buffer.Empty();
		buffer.FreeExtra();
		theApp.m_pMainWnd->GetDlgItem(IDC_MESSAGE)->SetWindowText(save);
	}
	closesocket(s);	//关闭套接字
	WSACleanup();
}

//点击发送按钮执行的代码。将消息发送出去,并显示在聊天记录中
void CTanc_mfc_chat_serverDlg::OnSendbutton() 
{
	//显示在聊天记录中
	UpdateData(TRUE);
	buffer.Format(_T("我说 :%s\r\n"),m_sendMessage);
	save = save + buffer;
	buffer.Empty();
	buffer.FreeExtra();
	m_message = save;
	UpdateData(FALSE);
	
	//发送消息
	sendbuf = m_sendMessage;
	len = sizeof(remote);
	sendto(s,sendbuf,strlen(sendbuf),0,(sockaddr*)&remote,len);
}
效果图:



二、客户端

客户端需要输入服务器IP地址和端口号,然后输入消息,进行发送。

//点击发送执行的代码
void CTanc_mfc_chat_clientDlg::OnSend() 
{
	//获取IP、端口号和发送的消息
	UpdateData(TRUE);
	BYTE nf1, nf2, nf3, nf4;
	m_serverIPAddress.GetAddress(nf1, nf2, nf3, nf4);
	sendbuf = m_sendMessage;
	int port = m_port;

	buffer.Format(_T("我说 :%s\r\n"),m_sendMessage);	
	save = save + buffer;
	buffer.Empty();
	buffer.FreeExtra();

	WSAStartup(0x101,&wsa);
	s = socket(AF_INET,SOCK_DGRAM,0);
	
	local.sin_family = AF_INET;
	local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	local.sin_port = htons(0x3412);

	bind(s,(sockaddr*)&local,sizeof(local));
	
	//确定IP和端口号
	remote.sin_family = AF_INET;
	remote.sin_addr.S_un.S_un_b.s_b1 = nf1;
	remote.sin_addr.S_un.S_un_b.s_b2 = nf2;
	remote.sin_addr.S_un.S_un_b.s_b3 = nf3;
	remote.sin_addr.S_un.S_un_b.s_b4 = nf4;
	remote.sin_port = htons(port);


	len = sizeof(remote);
	sendto(s,sendbuf,strlen(sendbuf),0,(sockaddr*)&remote,len);

	m_message = save;
	UpdateData(FALSE);

	//创建服务线程
	CreateThread(NULL, 0 ,ThreadClient, NULL, 0, NULL);
}

//用于显示接收消息的线程
DWORD WINAPI ThreadClient(LPVOID lpParameter)
{
	while(TRUE)
	{
		len = sizeof(remote);
		recvfrom(s,recvbuf,sizeof(recvbuf),0,(sockaddr*)&remote,&len);
		buffer.Format(_T("服务器说 :%s\r\n"),recvbuf);
		save = save + buffer;
		buffer.Empty();
		buffer.FreeExtra();
		theApp.m_pMainWnd->GetDlgItem(IDC_MESSAGE)->SetWindowText(save);
	}
	closesocket(s);
	WSACleanup();
}

效果图:



四、遇见的一些问题

1、CString类的buffer存放一次消息时,前次消息长于后次,前次多余的部分也会显示。如图:

//解决方法
buffer.Empty();
buffer.FreeExtra();

buffer = ""; //这种不行。

2、获取和写入界面数据的方法。
/*
用到了两种方法:
一个是获取ID的方法
二个是UpdateData()方法
*/
theApp.m_pMainWnd->GetDlgItem(IDC_MESSAGE)->SetWindowText(save);

UpdateData(TRUE);
UpdateData(FALSE);

//我表示没怎么区别搞懂,求具体的文档之类的~~~~

3、待续~~~

五、小结

基本完成了任务的要求,用线程实现了自由聊天,即随时都可以输入或显示对方的数据。对于C++还是不够了解,代码感觉好乱。







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值