C++ mfc版本socket通訊源碼分享


這是上個學期網絡通訊的課程設計所做的作業,C++語言中的MFC寫的。


後面將更新C#版本的基於socket的聊天室程序。廢話不多說,直接上源碼:








服務端代碼:


// sFileDlg.cpp : 實現文件
 //
 #include <winsock2.h>
 #include "stdafx.h"
 #include "sFile.h"
 #include "sFileDlg.h"
 #include "afxdialogex.h"
 #pragma comment(lib, "WS2_32.lib")

 #ifdef _DEBUG
 #define new DEBUG_NEW
 #endif


    UINT server_thd(LPVOID p); //聲明線程函數
 SOCKET listen_sock;//定義一個全局的監聽soket
 SOCKET sock;//定義一個soket
 CString showeditmsg; //定義全局的顯示消息的字符串

 
 
 // CsFileDlg 對話框
 CsFileDlg::CsFileDlg(CWnd* pParent /*=NULL*/)
 : CDialogEx(CsFileDlg::IDD, pParent)
{
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

 void CsFileDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialogEx::DoDataExchange(pDX);
}

 BEGIN_MESSAGE_MAP(CsFileDlg, CDialogEx)
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDC_BtnSend, &CsFileDlg::OnBnClickedBtnsend)
  ON_BN_CLICKED(IDC_BUTTON2, &CsFileDlg::OnBnClickedButton2)
 END_MESSAGE_MAP()


 // CsFileDlg 消息處理程序

 BOOL CsFileDlg::OnInitDialog()
 {
  CDialogEx::OnInitDialog();

  // 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
  //  執行此操作
  SetIcon(m_hIcon, TRUE);   // 設置大圖標
  SetIcon(m_hIcon, FALSE);  // 設置小圖標

  // TODO: 在此添加額外的初始化代碼
   show_edit = (CEdit *)GetDlgItem(IDC_EDIT1);
   send_edit = (CEdit *)GetDlgItem(IDC_EDIT2);
   port_edit = (CEdit *)GetDlgItem(IDC_EDIT3);
   star_btn =  (CButton *)GetDlgItem(IDC_BUTTON2);
   showmsg_edit =  (CEdit *)GetDlgItem(IDC_EDIT4);
  return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
 }


 

 // 如果向對話框添加最小化按鈕,則需要下面的代碼
 //  來繪製該圖標。對於使用文檔/視圖模型的 MFC 應用程序,
 //  這將由框架自動完成。

 void CsFileDlg::OnPaint()
 {
  if (IsIconic())
  {
   CPaintDC dc(this); // 用於繪製的設備上下文

   SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

   // 使圖標在工作區矩形中居中
   int cxIcon = GetSystemMetrics(SM_CXICON);
   int cyIcon = GetSystemMetrics(SM_CYICON);
   CRect rect;
   GetClientRect(&rect);
   int x = (rect.Width() - cxIcon + 1) / 2;
   int y = (rect.Height() - cyIcon + 1) / 2;

   // 繪製圖標
   dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
   CDialogEx::OnPaint();
  }
 }

 //當用戶拖動最小化窗口時系統調用此函數取得光標
 //顯示。
 HCURSOR CsFileDlg::OnQueryDragIcon()
 {
  return static_cast<HCURSOR>(m_hIcon);
 }


 //添加函數update() 更新消息數據
 void CsFileDlg::update(CString s)
 {
  showeditmsg += s;
  show_edit->SetWindowText(showeditmsg);
 }


 //開啓服務器按鈕響應事件
 void CsFileDlg::OnBnClickedButton2()
 {
  // TODO: 在此添加控件通知處理程序代碼
  WSADATA wsData; 
   WSAStartup(MAKEWORD(2,2), &wsData);

   char name[80];
   CString IP;
   CString P;
   hostent* pHost;
   gethostname(name,sizeof(name));//獲得主機名
   pHost = gethostbyname(name);//獲得主機結構
   IP = inet_ntoa(*(struct in_addr *)pHost->h_addr_list[1]);//獲取主機ip地址
   showmsg_edit->SetWindowText("綁定IP地址:" + IP);
   AfxBeginThread(&server_thd,0); //開啓新線程處理
 }



 //發送按鈕響應事件
 void CsFileDlg::OnBnClickedBtnsend()
 {
   // TODO: 在此添加控件通知處理程序代碼
  CString s;
  char * msg;
  send_edit->GetWindowText(s);
  msg = (char*)s.GetBuffer(s.GetLength()); //獲取發送的數據的緩衝區的指針

  if(s == "")
   {
        MessageBox("請輸入信息");
   }
   else if(send(sock, msg, strlen(msg), 0) == SOCKET_ERROR) //發送數據,並判斷是否成功
   {
     update("發送失敗\r\n");
   }
   else
   {
     update("我:" + s + "\r\n");//消息上屏
     send_edit->SetWindowText("");//清空輸入
     send_edit->SetFocus();//並重獲焦點
   }
 }


 
   //添加線程函數server_thd():
   UINT server_thd(LPVOID p)
  {
    WSADATA wsaData;
    WORD wVersion;
    wVersion = MAKEWORD(2,2);
    WSAStartup(wVersion,&wsaData);

    SOCKADDR_IN local_addr;
    SOCKADDR_IN client_addr;
    int iaddrSize = sizeof(SOCKADDR_IN);
    int res;
    char msg[1024];
    CString port;
    CsFileDlg * dlg = (CsFileDlg *)AfxGetApp()->GetMainWnd(); //得到應用程序活動主窗口的指針
    dlg->port_edit->GetWindowText(port);//獲得端口地址
    if(port=="")
    {
     AfxMessageBox("請輸入端口號");
     return 0;
    }
    //爲local_addr賦值,創建soket
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(atoi(port)); //atoi, 把字符串轉換成整型數
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
              //創建監聽listen_sock
    if( (listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET )
    {
     dlg->update("創建監聽失敗\r\n");
     return 0;
    }
    //綁定
    if( bind(listen_sock, (struct sockaddr*) &local_addr, sizeof(SOCKADDR_IN)) )
    {
    dlg->update("綁定錯誤,換一個端口試試吧~\r\n");
    return 0;
    }

    listen(listen_sock, 1); //開始監聽,允許最大監聽數爲1
    dlg->star_btn->EnableWindow(FALSE);  //開啓服務器按鈕灰化
    dlg->showmsg_edit->ShowWindow(SW_SHOW); //綁定消息edit顯示
    dlg->update("已成功開啓....\r\n");

    //接受連接請求
    if( (sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)
    {
    dlg->update("接受連接請求失敗\r\n");
    return 0;
    }
    else
    {
     CString port;
     port.Format("%d", int(ntohs(client_addr.sin_port)));
     dlg->update( "已連接來自:" + CString(inet_ntoa(client_addr.sin_addr)) + "  端口:" +
      port+"\r\n");
    }

     ////////////接收數據
    while(1)
    {
 
       if( (res = recv(sock, msg, 1024, 0)) == -1 ) //接收數據,判斷是否接收成功
       {
        dlg->update("失去連接\r\n");
        dlg->star_btn->EnableWindow(TRUE);
        break;
       }
       else
       {
        dlg->update("客戶端:" + (CString(msg)).Mid(0,res)+"\r\n");
       }
   
    }
     return 0;
   }





  客戶端代碼:


// cFileDlg.cpp : 實現文件
 //
 #include <winsock2.h>
 #include "stdafx.h"
 #include "cFile.h"
 #include "cFileDlg.h"
 #include "afxdialogex.h"
 #pragma comment(lib, "WS2_32.lib")

 #ifdef _DEBUG
 #define new DEBUG_NEW
 #endif


 SOCKET sock; //創建全局的soket
 UINT recv_thd(LPVOID p); //聲明線程函數
 CString edit1msg; // 定義全局的顯示消息的字符串


 // CcFileDlg 對話框

 CcFileDlg::CcFileDlg(CWnd* pParent /*=NULL*/)
  : CDialogEx(CcFileDlg::IDD, pParent)
 {
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 }

 void CcFileDlg::DoDataExchange(CDataExchange* pDX)
 {
  CDialogEx::DoDataExchange(pDX);
 }

 BEGIN_MESSAGE_MAP(CcFileDlg, CDialogEx)
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDC_SEND, &CcFileDlg::OnBnClickedSend)
  ON_BN_CLICKED(IDC_btnConnect, &CcFileDlg::OnBnClickedbtnconnect)
 END_MESSAGE_MAP()


 // CcFileDlg 消息處理程序

 BOOL CcFileDlg::OnInitDialog()
 {
   CDialogEx::OnInitDialog();

   // 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
   //  執行此操作
   SetIcon(m_hIcon, TRUE);   // 設置大圖標
   SetIcon(m_hIcon, FALSE);  // 設置小圖標

   // TODO: 在此添加額外的初始化代碼
   //初始化

    edit1 = (CEdit *)GetDlgItem(IDC_EDIT1);
    send_edit = (CEdit *)GetDlgItem(IDC_EDIT2);
    btnconn = (CButton *)GetDlgItem(IDC_btnConnect);
    ip_edit = (CEdit *)GetDlgItem(IDC_EDIT3);
    port_edit = (CEdit *)GetDlgItem(IDC_EDIT4);
    ip_edit->SetWindowText("127.0.0.1");
  return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
 }


 // 如果向對話框添加最小化按鈕,則需要下面的代碼
 //  來繪製該圖標。對於使用文檔/視圖模型的 MFC 應用程序,
 //  這將由框架自動完成。

 void CcFileDlg::OnPaint()
 {
  if (IsIconic())
  {
   CPaintDC dc(this); // 用於繪製的設備上下文

   SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

   // 使圖標在工作區矩形中居中
   int cxIcon = GetSystemMetrics(SM_CXICON);
   int cyIcon = GetSystemMetrics(SM_CYICON);
   CRect rect;
   GetClientRect(&rect);
   int x = (rect.Width() - cxIcon + 1) / 2;
   int y = (rect.Height() - cyIcon + 1) / 2;

   // 繪製圖標
   dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
   CDialogEx::OnPaint();
  }
 }

 //當用戶拖動最小化窗口時系統調用此函數取得光標
 //顯示。
 HCURSOR CcFileDlg::OnQueryDragIcon()
 {
  return static_cast<HCURSOR>(m_hIcon);
 }




      //更新顯示窗口數據
 void CcFileDlg::update(CString s) 
 {
  edit1msg += s;
  edit1->SetWindowText(edit1msg);
 }


     //鏈接,點連接按鈕執行事件
 void CcFileDlg::OnBnClickedbtnconnect()
 {
  // TODO: 在此添加控件通知處理程序代碼

  WSADATA wsaData;
  SOCKADDR_IN server_addr;


   WORD wVersion;
   wVersion = MAKEWORD(2,2);
   WSAStartup(wVersion,&wsaData);//使用Socket的程序在使用Socket之前必須調用WSAStartup函數。
   //該函數的第一個參數指明程序請求使用的Socket版本,其中高位字節指明副版本、低位字節指明主版本;
   //操作系統利用第二個參數返回請求的Socket的版本信息。
  //當一個應用程序調用WSAStartup函數時,操作系統根據請求的Socket版本來搜索相應的Socket庫,
  //然後綁定找到的Socket庫到該應用程序中。以後應用程序就可以調用所請求的Socket庫中的其它Socket函數了。
  //該函數執行成功後返回0

   CString ip;
   CString port;
   ip_edit->GetWindowText(ip);//取得服務器的IP地址
   port_edit->GetWindowText(port);//取得服務器的端口

   if(port=="") //判斷端口是否爲空
   {
    AfxMessageBox("請輸入端口號");
    btnconn->EnableWindow(TRUE);
    return;
   }

   //爲server_addr賦值 ,創建soket
   server_addr.sin_addr.s_addr = inet_addr((LPCSTR)ip);
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(atoi(port));

   if( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) //判斷soket是否創建成功
   {
     update("創建Soket錯誤!\r\n");
     btnconn->EnableWindow(TRUE);
     return;
   }
   if( connect(sock, (struct sockaddr *) &server_addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)//判斷鏈接是否成功
   {
     update("連接失敗\r\n");
     btnconn->EnableWindow(TRUE);
     return;
   }
   else
   {
     update("連接成功\r\n");
     AfxBeginThread(&recv_thd, 0); //開啓線程處理
     btnconn->EnableWindow(FALSE);//連接按鈕變灰
   }
 }


//發送消息按鈕處理事件
  void CcFileDlg::OnBnClickedSend()
   {

   CString s;
   char * msg;
   send_edit->GetWindowText(s);
   msg = (char*)s.GetBuffer(s.GetLength()); //獲取發送的數據的緩衝區的指針

   if(send(sock, msg, strlen(msg), 0) == SOCKET_ERROR) //判斷髮送是否成功
   {
     update("發送失敗\r\n");
   }
   else if(s == "")   //判斷髮送的數據是否爲空
   {
        MessageBox("請輸入信息");
   }
   else
   {
     update("我:"+ s+"\r\n");//消息上屏
     send_edit->SetWindowText("");//清空輸入
     send_edit->SetFocus(); //重獲焦點
   }
 }


//添加線程函數,接收數據
  UINT recv_thd(LPVOID p)
 {
  int res;
  char msg[1024];
  CString s;
  CcFileDlg * dlg = (CcFileDlg *) AfxGetApp()->GetMainWnd(); //得到應用程序活動主窗口的指針
  dlg->update("開始聊天吧~\r\n");
 
  while(1)
  {
        if( (res = recv(sock, msg, 1024, 0)) == -1) //接收數據,判斷是否接收成功
    {
     dlg->update("失去連接~\r\n");
     dlg->btnconn->EnableWindow(TRUE);
     break;
    }
    else
    {
         dlg->update("服務器:" + (CString(msg)).Mid(0,res)+ "\r\n");
    }
  }
  return 0;
 }





                         作者QQ:575674261

            

                         

                        .NET學習交流羣 :324087998  (更多實戰項目源碼分享)




完整代碼打包:  http://pan.baidu.com/s/1sj0KarN







發佈了40 篇原創文章 · 獲贊 7 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章