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

从本节开始,从IM的功能出发,以及代码展示来实现IM客户端:
从第一个用例开始:注册
注册按钮是放置在登陆界面上的,笔者的登陆界面展示如下:

单击注册按钮后,出现如下界面:

如图所示,登陆界面是程序的主对话框,客户端的注册框的任务是:
1)建立客户端与服务端链接//这一步在CRegister::OnInitDialog()中执行
2)填写注册信息
3)检查信息格式//此步以及后面的步骤在CRegister::OnOK()中执行
4)发送注册包
5)接受服务端的反馈包
8)断开与服务端的链接

根据上面的流程,当填好注册信息后,主要执行代码如下:

BOOL CRegister::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here
	//设置默认性别
	((CButton *)GetDlgItem(IDC_RADIO3))->SetCheck(TRUE);//选上
	sex=0x04;
	//添加代码--〉向服务器申请登陆
	BYTE *pIP;//获取IP控件Address
	CString strIP;
	DWORD dwIP;
	CWnd *pWnd=GetParent();
	((CLoggingDlg *)pWnd)->m_Address.GetAddress(dwIP);
	pIP = (unsigned   char*)&dwIP;
	strIP.Format( "%u.%u.%u.%u ",*(pIP+3), *(pIP+2), *(pIP+1), *pIP);
	//链接
	extern CTCPSocket sock;
	if(sock.SetupTCPClientSocket(strIP, ((CLoggingDlg *)pWnd)->m_strPort)<0)
		{
			::MessageBox(NULL,"socket() or connect() failed","system error",MB_OK|MB_ICONERROR);
		}
		else//链接成功
		{
			sock.rio_readinitb(sock.rio, sock.sock);
		}
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}
void CRegister::OnOK() 
{
	// 本地数据检验与处理
	UpdateData(TRUE);
	if(m_ByteAge>130)
		::MessageBox(NULL,"年龄范围在0-130之间","错误信息",MB_OK|MB_ICONERROR);
	if(m_strPass!=m_strRePass)
	::MessageBox(NULL,"两次密码输入不一致","错误信息",MB_OK|MB_ICONERROR);
	m_strName.TrimLeft();
	m_strName.TrimRight();

	//发送数据
	extern CTCPSocket sock;

	cln_register reg;
	reg.magic=0x54;
	reg.flags=0x02;
	sprintf(reg.name,"%s",m_strName);
	sprintf(reg.pass,"%s",m_strPass);
	sprintf(reg.city,"%s",m_strCity);
	reg.age=m_ByteAge;
	reg.sex=sex;
	sprintf(reg.info,"%s",m_strInfo);
	int num;
	if((num=sock.rio_writeline(sock.sock, ®, sizeof(reg), 0))<0)
		::MessageBox(NULL,"发送注册消息失败","system error",MB_OK|MB_ICONERROR);
	//接受数据
	char buf[88];
	int size=sock.rio_readlineb(sock.rio, buf, sizeof(buf));
	serv_register *serv_reg=(serv_register *)buf;
	if(serv_reg->magic==0x55 && serv_reg->flags==0x02)
	{
		CString str="注册成功,id:";
		str += serv_reg->id;
		str += "密码:";
		str += serv_reg->pass;
		::MessageBox(NULL,str,"system error",MB_OK);
		closesocket(sock);//关闭TCP套接字
		CDialog::OnOK();
	}
	else
	{
		::MessageBox(NULL,"注册失败,请重新注册","system error",MB_OK|MB_ICONERROR);
	}
}

 
以上就是注册用例了,可以看出明显的缺陷是:每次注册都会链接一次服务器,注册结束后直接回到登陆界面,关于注册失败也没有采取保留措施,导致用户友好性不是很好,不过这些都可以改善,读者有兴趣可以试一试;

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

既然讲了注册,下面就将登陆一并讲了吧:
客户端的登陆任务步骤如下:
1)建立客户端与服务端链接
2)输入登录信息
3)本地校验输入信息格式错误
4)发送登录请求
5)接受服务端的反馈包
6)分析包:登陆成功或失败(成功则进入好友界面,接受好友信息)

根据上面的流程,当填好登陆信息后,主要执行代码如下:

BOOL CLoggingDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here
	m_ButtonCheckPort.SetCheck(BST_CHECKED);//默认自动获取port
	if(m_ButtonCheckPort.GetCheck())
	{
		m_EditPort.EnableWindow(FALSE);
	}
	m_ButtonIp.SetCheck(BST_CHECKED);//使用默认IP
	if(m_ButtonIp.GetCheck())
	{
		m_Address.EnableWindow(FALSE);
	}
	//设置IP默认值
	CString strIP = "127.0.0.1 ";
	DWORD  dwIP = inet_addr(strIP);
	BYTE *pIP = (BYTE*)&dwIP;
	m_Address.SetAddress(*pIP, *(pIP+1), *(pIP+2), *(pIP+3));

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CLoggingDlg::OnCheckPort() 
{
	// TODO: Add your control notification handler code here
	if(m_ButtonCheckPort.GetCheck())
	{
		m_EditPort.EnableWindow(FALSE);
	}
	else
		m_EditPort.EnableWindow(TRUE);
}


void CLoggingDlg::OnCheckIp() 
{
	// TODO: Add your control notification handler code here
	if(m_ButtonIp.GetCheck())
	{
		m_Address.EnableWindow(FALSE);
	}
	else
		m_Address.EnableWindow(TRUE);
}

void CLoggingDlg::OnOK() {  // TODO: 本地校验  this->UpdateData(TRUE);  if((strcmp(this->m_strUserId,"")==0) || (strcmp(this->m_strPassword ,"")==0))  {   ::MessageBox(NULL,"用户名或口令不能为空!","错误信息",MB_OK|MB_ICONERROR);  }   else   {    this->UpdateData(TRUE);    //添加代码--〉向服务器申请登陆    BYTE *pIP;//获取IP控件Address    CString strIP;    DWORD dwIP;    m_Address.GetAddress(dwIP);    pIP = (unsigned   char*)&dwIP;    strIP.Format( "%u.%u.%u.%u ",*(pIP+3), *(pIP+2), *(pIP+1), *pIP);    //生成链接socket    extern CTCPSocket sock;    //extern rio_t rio;        if(sock.SetupTCPClientSocket(strIP, m_strPort)<0)    {     ::MessageBox(NULL,"socket() or connect() failed","system error",MB_OK|MB_ICONERROR);    }     else//链接成功     {      sock.rio_readinitb(sock.rio, sock.sock);      cln_log log;      log.magic=0x54;      log.flags=0x01;      sprintf(log.userid,"%s",m_strUserId);      sprintf(log.password,"%s",m_strPassword);      char buf[10];      memset(buf,'\0',sizeof(buf));      int num;      if((num=sock.rio_writeline(sock.sock, &log, sizeof(log), 0))<=0)       ::MessageBox(NULL,"rio_writen() failed","system error",MB_OK|MB_ICONERROR);

     int size=sock.rio_readlineb(sock.rio, buf, sizeof(buf));

     if(size>0)      {       header *servlog =(header *)buf;       if((servlog->magic==0x55) && (servlog->flags==0x01))        //登录成功        CDialog::OnOK();//打开好友聊天界面对话框       else        if((servlog->magic==0x54) && (servlog->flags==0x01))         ::MessageBox(NULL,"登录失败","system error",MB_OK|MB_ICONERROR);        else         ::MessageBox(NULL,"数据包不在服务范围内","system error",MB_OK|MB_ICONERROR);      }     }   } }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值