现在的位置: 首页 > 综合 > 正文

10.3.2 客户端

2013年03月27日 ⁄ 综合 ⁄ 共 6341字 ⁄ 字号 评论关闭

  客户端实现步骤如下。

1 打开VC6,单击【File|New】命令,弹出【New】对话框。

2)在【Projects】选项卡中,选择【MFC AppWizard(exe)】选项,创建一个MFC应用程序。在【Projectname】文本框中,输入项目名称“client”,如图10.18所示。


10.18 新建VC工程

3)单击“OK”,在创建MFC应用程序向导对话框选择应用程序类型,这里选择“Dilag based”如图10.19所示。然后单击“Finish”完成。

                                                     

(4)IDD_CLIENT_DIALOG对话框窗体添加编辑框(Edit Box)控件。

(5) Ctrl+W 键或单击【View|ClassWizard】命令,启动“MFC ClassWizard”,对话框,选择【Member Variables】选项。如图所示。

6)选中“IDC_EDIT1”控件,单击“Add Variable…”按钮。添加CString变量m_str,如图所示。

(7)IDD_ CLIENT _DIALOG对话框窗体添加列表框(List Box)控件。

(8) Ctrl+W 键或单击【View|ClassWizard】命令,启动“MFC ClassWizard”,对话框,选择【Member Variables】选项。如图所示。

9)选中“IDC_LIST”控件,单击“Add Variable…”按钮。添加控件变量m_list,如图所示。

10)在IDD_ CLIENT _DIALOG对话框窗体,添加三个命令按钮(Button)控件。全部控件和布局如图所示。

11)添加自定义结构体,用户保存SSL链接句柄。在serverDlg.cpp添加如下代码

typedef struct descriptor{

         int     fd;

         SSL  *ssl;

}descriptor_t;

SSL_CTX* ctx;

descriptor_t client;

12BOOL CClientDlg::OnInitDialog()函数中添加如下代码初始化客户端环境。

         // TODO: Add extra initialization here

         //初始化OpenSSL环境

         client.fd=0;

         client.ssl=NULL;

         SSLeay_add_ssl_algorithms();

         SSL_load_error_strings();

         ctx = SSL_CTX_new (SSLv23_client_method());//设置SSL协议版本

         return TRUE;  // return TRUE  unless you set the focus to a control

13BOOL CClientDlg:: OnConnect ()函数即“连接”,按钮中添加如下代码连接服务器。

//链接服务器

void CClientDlg::OnConnect()

{

                  

         unsigned long           idThread;

         DWORD dwIP=0;

         if(client.fd==0)//判断是否已经连接

         {

                   CIP ipaddr;//让用户输入客户端IP

                   if(ipaddr.DoModal() == IDOK)

                   {

                           

                            dwIP=inet_addr(ipaddr.IP.GetBuffer(0));

                   }

                   //创建线程,连接服务器,并接收服务器端消息

                   CreateThread(NULL,0,

                            (LPTHREAD_START_ROUTINE)ClientThreadProc,

                            (void *)dwIP, 0 ,&idThread);

         }

         else

         {

                   m_list.InsertString(0,"已经连接!");

         }

}

14 ClientThreadProc函数连接服务器端并接收服务器消息的线程处理函数,其代码如下

//连接服务器端并接收服务器消息的线程函数

void ClientThreadProc(void* void_parm)

{

         WSADATA              wsaData;

         int err;

         int sd;

         struct sockaddr_in sa;

         SSL*     ssl;

         X509*    server_cert;

         char*    str;

         char     buffer [8912];

         int     maxFd;

         fd_set       writeFds, readFds, excFds;

         DWORD dwIP;

         dwIP = (DWORD)void_parm;

         //初始化windows socket

         if (WSAStartup(MAKEWORD(1, 1), &wsaData))

         {

                   return;

         }

         //新建socket

         sd = socket (AF_INET, SOCK_STREAM, 0);

         memset (&sa, '/0', sizeof(sa));

         //设置服务端IP地址、和端口

         sa.sin_family      = AF_INET;

         sa.sin_addr.s_addr = dwIP;

         sa.sin_port        = htons(8443);

         //连接服务器

         err = connect(sd, (struct sockaddr*) &sa,

                   sizeof(sa));  

         if(err < 0)

         {

                   char *msg = (char *)malloc(128);

                   strcpy(msg,"连接服务器失败!");

                   SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,sd,(long )msg);            

                   return;

         }

         //新建SSL句柄

         ssl = SSL_new (ctx);  

    //设置socket句柄到SSL句柄

         SSL_set_fd (ssl, sd);

         //SSL连接

         err = SSL_connect (ssl);

         if(err != 1)

         {

                   char *msg = (char *)malloc(128);

                   strcpy(msg,"连接服务器失败!");

                   SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,sd,(long )msg);            

                   return;

         }

         server_cert = SSL_get_peer_certificate (ssl);

    str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);

         OPENSSL_free (str);

         str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);

         OPENSSL_free (str);

         X509_free (server_cert);

         printf ("SSL connection using %s/n", SSL_get_cipher (ssl));

         maxFd = sd;

         client.fd=sd;

         client.ssl=ssl;

         char *msg = (char *)malloc(128);

         strcpy(msg,"连接服务器成功!");

         SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,sd,(long )msg);

        

         for(;;)

         {

                   FD_ZERO(&writeFds);

                   FD_ZERO(&readFds);

                   FD_ZERO(&excFds);

                   FD_SET(sd, &readFds);

                   //select 异步等待服务器

                   int nfd = select(maxFd + 1, &readFds, &writeFds, &excFds, NULL);

                   if(nfd <= 0)

                   {

                            if(errno == EINTR)    /* interrupted system call */

                                     continue;

                            return;

                   }

                   if(FD_ISSET(sd, &readFds))

                   {

                            //接收服务器消息

                            int len = SSL_read(ssl,buffer,sizeof(buffer));

                            if(len <=0)

                            {

                                     char *msg = (char *)malloc(128);

                                     strcpy(msg,"服务器退出!");

                                     SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,sd,(long )msg);

                                     return;

                            }

                            buffer[len]='/0';

                            char *msg = (char *)malloc(len +1);

                            strcpy(msg,buffer);

                            //通过WM_CLIENT_MSG消息,发送到主窗体

                            SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,sd,(long )msg);

                   }

         }

         return;

}

15void CClientDlg:: OnSend ()函数即“Send”按钮中添加如下代码,向服务器端发送消息。

//发送消息到服务器

void CClientDlg::OnSend()

{

         UpdateData();

         if(client.fd !=0)

         {

                   //发送消息

                   SSL_write(client.ssl,m_str.GetBuffer(0),m_str.GetLength());

                   m_str.ReleaseBuffer();

         }

         else

         {

                   return;

         }

         //插入发送的消息的列表框

         m_list.InsertString(0,m_str);

         m_str.Empty();

         UpdateData(FALSE);

         ((CEdit *)GetDlgItem(IDC_EDIT1))->SetActiveWindow(); 

}

16void CClientDlg:: OnDisconnect ()函数即“取消”按钮中添加如下代码,断开与服务器的链接。

//断开链接

void CClientDlg::OnDisconnect()

{

         if(client.fd !=0)

         {

                   closesocket(client.fd);

                   SSL_shutdown(client.ssl);

                   SSL_free(client.ssl);

                   client.ssl=NULL;

                   client.fd=0;

                   m_list.InsertString(0,"已断开和服务器的链接!");

         }

}

(17)添加处理WM_CLIENT_MSG消息的函数OnClientMsg ()。其代码如下:

//处理WM_CLIENT_MSG消息

LRESULT CClientDlg::OnClientMsg(WPARAM wParam,LPARAM lParam)

抱歉!评论已关闭.