MFC實現簡單的聊天功能
阿新 • • 發佈:2018-12-21
設計目標:
2.設計二 簡單的即時通訊軟體(6學時實驗)
目的與要求: 利用WinSock進行點對點通訊,工作機制模仿即時通訊軟體的基本功能,登陸,上線,傳遞資訊等等。分為客戶部分和伺服器部分兩塊,客戶部分類似一般通訊軟體例如QQ,伺服器部分主要提供客戶端使用者基本資料配置。
服務端程式碼:
#include <WinSock2.h> #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <string> #include <sstream> #pragma comment(lib,"pthreadVC2.lib") #pragma comment(lib,"ws2_32.lib") #include<iostream> using namespace std; /*void* recv1(SOCKET sockConn) { char recvBuf[10000]; memset(recvBuf, 0, sizeof(recvBuf)); //接收資料 while(true){ int nRecv = ::recv(sockConn, recvBuf, sizeof(recvBuf), 0); cout<<endl; if(nRecv>0)cout<<"他說:"<<recvBuf<<endl; else break;} }*/ SOCKET sockConn[10]; char password[] = "123456"; int pass = 0; const int nl = 100; string user[nl] = { "123","456","789","張三" }; string pw[nl] = { "111","456","789","張三" }; int online[nl] = {0,0,0};//判斷是否線上的陣列 int match[nl] = {-1,-1,-1};//表示第i個使用者名稱匹配的是第幾個套接字 int find(string a[], string b) { bool exist = false; for (int j = 0; j<nl; j++) { if (a[j] == b) { exist = true; return j; } } if (!exist) return -1; } int find1(SOCKET sock) { for (int i = 0; i < 10; i++) { if (sock == sockConn[i]) { return i; break; } } return -1; } int finds(string s)//根據使用者名稱找到對應的套接字 { int index = find(user,s); if (index >= 0) return match[index]; else return -1; } int findu(SOCKET sock )//根據套接字找使用者名稱在陣列中的位置 { int index = find1(sock); for (int i = 0; i < nl; i++) { if (match[i] == index) return i; } return -1; } int nul_index(string a[])//查詢string陣列的空位,以便於使用者註冊的插入 { for (int i = 0; i < nl; i++) { if (a[i].empty()) return i; } return nl;//沒有空位,註冊已滿 } void* recv1(void* args) { char recvBuf[10000]; char users[1000]; char pws[1000]; //接收資料 bool success = false;//判斷是否登入成功 int id1 = (unsigned int)pthread_getw32threadid_np(pthread_self()) / 2; SOCKET sockConn1 = *((SOCKET*)args);//建立套接字 memset(recvBuf, 0, sizeof(recvBuf)); int rel = 0; rel = recv(sockConn1, recvBuf, sizeof(recvBuf), 0); if (rel<0) cout << "接受失敗\n"; cout << rel<<" "<<recvBuf<<endl; send(sockConn1, "ack", sizeof(recvBuf),0); //cout<<recvBuf<<endl; if (strcmp(recvBuf, "1") == 0)//客戶端選擇登入 { cout << "選擇登入服務\n"; memset(users, 0, sizeof(users)); rel = recv(sockConn1, users, sizeof(users), 0); if (rel<0)//接受使用者名稱 cout << "recv failed"; cout <<rel<<" "<< users << endl; send(sockConn1, "ack", sizeof(recvBuf),0); int index = find(user, users);//判斷能否找到使用者名稱 int sockNum = find1(sockConn1); if (index != -1)//找到使用者名稱 { if (online[index] == 0) { cout << "找到使用者名稱" << endl; memset(pws, 0, sizeof(pws)); if (recv(sockConn1, pws, sizeof(pws), 0) < 0)//接受密碼 cout << "recv failed"; cout << pws << endl; if (pws == pw[index])//密碼正確 { online[index] = 1; success = true; match[index] = sockNum; if (send(sockConn1, "密碼正確", sizeof(recvBuf), 0) < 0) { cout << "傳送失敗"; } } else//密碼錯誤 { send(sockConn1, "密碼錯誤", sizeof(recvBuf), 0); } } else { memset(pws, 0, sizeof(pws)); if (recv(sockConn1, pws, sizeof(pws), 0)<0)//接受密碼 cout << "recv failed"; if (send(sockConn1, "該使用者已存在", sizeof(recvBuf), 0)<0) cout << "傳送失敗"; } } if (index == -1)//未找到使用者名稱 { memset(pws, 0, sizeof(pws)); if (recv(sockConn1, pws, sizeof(pws), 0)<0)//接受密碼 cout << "recv failed"; if (send(sockConn1, "使用者名稱不存在", sizeof(recvBuf), 0)<0) cout << "傳送失敗"; } if (success) { char buf[1000]; int id = find1(sockConn1); int n = findu(sockConn1); const char*p=user[n].data(); //user[n].copy(p, 40, 0);//這裡5,代表複製幾個字元,0代表複製的位置 //*(p + 40) = '\0';//要手動加上結束符 if (id >= 1) { for (int j = 1; j < id + 1; j++)//好友上線功能 { if (send(sockConn[j - 1], p, sizeof(p), 0) < 0) //,sizeof(buf),0)<0) cout << "send failed"; if (send(sockConn[j - 1], "已上線", sizeof(buf), 0) < 0) cout << "send failed"; } } while (true) { memset(recvBuf, 0, sizeof(recvBuf)); recv(sockConn1,recvBuf,sizeof(recvBuf),0);//接受要傳送的使用者名稱 int index = find(user,recvBuf);//查詢要傳送使用者名稱的位置 if(strcmp(recvBuf, "all") == 0)//實現群發 { memset(recvBuf, 0, sizeof(recvBuf)); recv(sockConn1, recvBuf, sizeof(recvBuf), 0); for (int i = 0; i < nl; i++) { if (online[i] == 1&&i!=findu(sockConn1)) { string a = user[n] + ": "; const char* pp = a.data(); sockNum = finds(user[i]); if (send(sockConn[sockNum], pp, sizeof(pp), 0) < 0) //,sizeof(buf),0)<0) cout << "send failed"; send(sockConn[sockNum], recvBuf, sizeof(recvBuf), 0); } } } else { if (strcmp(recvBuf, "退出") == 0)//使用者選擇退出 { int i = findu(sockConn1); online[i] = 0; closesocket(sockConn1); } if (online[index]==1&&index != -1) { int sockNum = match[index];//找到此使用者名稱的套接 int nRecv = ::recv(sockConn1, recvBuf, sizeof(recvBuf), 0); cout << endl; if (nRecv > 0)//實現轉發給其他客戶端 { string a=user[n] +": ";//實現能看到是誰發的 cout << id1 << "號客戶說:" << recvBuf << endl; const char* ppp = a.data(); send(sockConn[sockNum], ppp, sizeof(recvBuf), 0); send(sockConn[sockNum], recvBuf, sizeof(recvBuf), 0); //send(sockConn1, "傳送的使用者名稱存在", sizeof(recvBuf), 0); //if (send(sockConn[0], recvBuf, sizeof(recvBuf), 0) < 0) //cout << "傳送失敗"; //send(sockConn[0], recvBuf, sizeof(recvBuf), 0); } else break; } if (online[index] == 0&&index!=-1) { memset(recvBuf, 0, sizeof(recvBuf)); recv(sockConn1, recvBuf, sizeof(recvBuf), 0); send(sockConn1, "使用者不線上", sizeof(recvBuf), 0); } if(index==-1)//傳送的使用者名稱不存在 { memset(recvBuf, 0, sizeof(recvBuf)); recv(sockConn1, recvBuf, sizeof(recvBuf), 0); send(sockConn1, "傳送的使用者名稱不存在", sizeof(recvBuf), 0); } } } } } if (strcmp(recvBuf, "2") == 0) //客戶端選擇註冊 { cout << "選擇註冊服務" << endl; memset(users, 0, sizeof(users)); if (recv(sockConn1, users, sizeof(users), 0) < 0)//接收使用者名稱 cout << "register failed" << endl; int index = find(user, users);//看看是否已存在使用者名稱 send(sockConn1, "ack", sizeof(recvBuf), 0); //cout << index <<users << endl; if (index != -1)//find { cout << "使用者名稱已存在" << endl; if (send(sockConn1, "使用者名稱已存在", sizeof(recvBuf), 0) < 0) { cout << "使用者註冊失敗" << endl; } } if (index == -1)//register { cout << "使用者名稱未註冊過" << endl; memset(pws, 0, sizeof(pws)); if (recv(sockConn1, pws, sizeof(pws), 0) < 0)//接收密碼 cout << "failed pws" << endl; else//接收密碼 新增使用者和密碼 { cout << "已經接收到密碼" << pws << endl; int location = nul_index(user);//尋找可以插入的空位 cout << "找到空位在1+" << location << endl; if (location == nl)//插入已滿 { cout << "註冊已滿" << endl; if (send(sockConn1, "註冊已滿", sizeof(recvBuf), 0) < 0)//發給客戶已滿資訊 cout << "send failed" << endl; } else//註冊 { cout << "開始註冊:" << endl; user[location] = users; pw[location] = pws; cout << pw[location] << "aaa" << user[location] << endl; if (send(sockConn1, "註冊成功", sizeof(recvBuf), 0) < 0)//發給客戶已滿資訊 cout << location + 1 << "位使用者" << "註冊成功" << endl; } } } } return recvBuf; } void* send1(void* args) { int id2 = (unsigned int)pthread_getw32threadid_np(pthread_self()) / 2; SOCKET sockClient1 = *((SOCKET*)args);//建立套接字 char buff1[10000]; while (true) { //cout<<"請輸入"<<endl; cin >> buff1; if (buff1 == "") { break; } int e = send(sockConn[0], buff1, sizeof(buff1), 0); if (e == SOCKET_ERROR) { printf("send failed"); break; } /*e = send(sockConn[1], buff1, sizeof(buff1), 0); if (e == SOCKET_ERROR) { printf("send failed"); break; } cout << "我說:" << buff1 << endl;*/ } return buff1; } void* setClient(void* args) { char buf[10000] = "Server: hello, I am a server....."; SOCKET sockClient = *((SOCKET*)args);//建立套接字 // printf("Accept client IP:[%s]\n", inet_ntoa(addrClient.sin_addr)); //傳送資料 //send1(sockConn); int iSend = send(sockClient, buf, sizeof(buf), 0); if (iSend == SOCKET_ERROR) { printf("send failed"); } pthread_t tidss[2]; int ret = pthread_create(&tidss[0], NULL, send1, (void*)&sockClient); //引數:建立的執行緒id,執行緒引數,執行緒執行函式的起始地址,執行函式的引數 if (ret != 0) //建立執行緒成功返回0 { cout << "pthread_create error:error_code=" << ret << endl; } recv1((void*)&sockClient); return buf; } int main() { WSADATA wsaData;//WSADATA結構被用來儲存函式WSAStartup返回的Windows Sockets初始化資訊 int port = 5099; char buf[] = "Server: hello, I am a server....."; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) //載入套接字型檔 { printf("Failed to load Winsock"); return 0; } //建立用於監聽的套接字 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);//ipv4協議,流式傳輸 SOCKADDR_IN addrSrv;//此資料結構用做bind、connect、recvfrom、sendto等函式的引數,指明地址資訊。 addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port); //1024以上的埠號 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //INADDR_ANY 代表任意ip //繫結套接字 int retVal = bind(sockSrv, (LPSOCKADDR)&addrSrv, sizeof(SOCKADDR_IN)); if (retVal == SOCKET_ERROR) { printf("Failed bind:%d\n", WSAGetLastError()); return 0; } if (listen(sockSrv, 10) == SOCKET_ERROR) {//10代表允許連線的個數 printf("Listen failed:%d", WSAGetLastError()); return 0; } SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); int i = 0; while (1) { //等待客戶請求到來 sockConn[i] = accept(sockSrv, (SOCKADDR *)&addrClient, &len);//會阻塞程序,直到有客戶端連線上來為止 if (sockConn[i] == SOCKET_ERROR) { printf("Accept failed:%d", WSAGetLastError()); break; } pthread_t tids[10]; int res = pthread_create(&tids[i], NULL, setClient, (void*)&sockConn[i]); if (res != 0) //建立執行緒成功返回0 { cout << "pthread_create error:error_code=" << res << endl; } i++; } closesocket(sockSrv); WSACleanup(); system("pause"); return 1; }
客戶端核心程式碼:
介面1:
// connent1Dlg.cpp: 實現檔案 // #include "stdafx.h" #include "connent1.h" #include "connent1Dlg.h" #include "afxdialogex.h" #include <WinSock2.h> #include <stdio.h> #include <pthread.h> #include <io.h> #include <fcntl.h> #pragma comment(lib, "pthreadVC2.lib") #pragma comment(lib, "ws2_32.lib") #include<iostream> #include "Cmessage.h" using namespace std; #ifdef _DEBUG #define new DEBUG_NEW #endif char user[10]; char pw[20]; Cmessage Dlg; int num; char buff[1000]; char nUser[1000]; //SOCKET sockClient; bool success = false; class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 對話方塊資料 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支援 // 實現 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // Cconnent1Dlg 對話方塊 Cconnent1Dlg::Cconnent1Dlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_CONNENT1_DIALOG, pParent) , m_user(_T("")) , m_pw(_T("")) //, m_show(_T("")) //, m_message(_T("")) //, sUser(_T("")) //, suser(_T("")) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void Cconnent1Dlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); //DDX_Control(pDX, IDC_EDIT1, user); DDX_Text(pDX, IDC_EDIT2, m_pw); DDX_Text(pDX, IDC_EDIT1, m_user); //DDX_Text(pDX, IDC_EDIT3, m_show); //DDX_Text(pDX, IDC_EDIT4, m_message); //DDX_Control(pDX, IDC_EDIT3, edit3); //DDX_Text(pDX, IDC_EDIT5, sUser);//之前的類變數使用者名稱重複。不區分大小寫 //DDX_Text(pDX, IDC_EDIT7, suser); //DDX_Control(pDX, IDC_COMBO1, m_chosecom); } BEGIN_MESSAGE_MAP(Cconnent1Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_EN_CHANGE(IDC_EDIT1, &Cconnent1Dlg::OnEnChangeEdit1) ON_BN_CLICKED(IDC_BUTTON1, &Cconnent1Dlg::OnBnClickedButton1) //ON_BN_CLICKED(IDC_BUTTON2, &Cconnent1Dlg::OnBnClickedButton2) ON_BN_CLICKED(IDC_BUTTON3, &Cconnent1Dlg::OnBnClickedButton3) //ON_CBN_SELCHANGE(IDC_COMBO1, &Cconnent1Dlg::OnCbnSelchangeCombo1) END_MESSAGE_MAP() // Cconnent1Dlg 訊息處理程式 BOOL Cconnent1Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 將“關於...”選單項新增到系統選單中。 // IDM_ABOUTBOX 必須在系統命令範圍內。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 設定此對話方塊的圖示。 當應用程式主視窗不是對話方塊時,框架將自動 // 執行此操作 SetIcon(m_hIcon, TRUE); // 設定大圖示 SetIcon(m_hIcon, FALSE); // 設定小圖示 // TODO: 在此新增額外的初始化程式碼 //edit3 = (CEdit *)GetDlgItem(IDC_EDIT3); //GetDlgItem(IDC_EDIT4)->SetWindowText(_T("this is a test program!")); return TRUE; // 除非將焦點設定到控制元件,否則返回 TRUE } void Cconnent1Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向對話方塊新增最小化按鈕,則需要下面的程式碼 // 來繪製該圖示。 對於使用文件/檢視模型的 MFC 應用程式, // 這將由框架自動完成。 void Cconnent1Dlg::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 Cconnent1Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void Cconnent1Dlg::OnEnChangeEdit1() { // TODO: 如果該控制元件是 RICHEDIT 控制元件,它將不 // 傳送此通知,除非重寫 CDialogEx::OnInitDialog() // 函式並呼叫 CRichEditCtrl().SetEventMask(), // 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。 // TODO: 在此新增控制元件通知處理程式程式碼 } void Cconnent1Dlg::OnBnClickedButton1() { // TODO: 在此新增控制元件通知處理程式程式碼 UpdateData(true); //載入套接字 WSADATA wsaData; char buff[10000]; memset(buff, 0, sizeof(buff)); if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Failed to load Winsock"); //return 0; } SOCKADDR_IN addrSrv; //服務端地址 addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(5099); addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1 "); //建立客戶端套接字 sockClient = socket(AF_INET, SOCK_STREAM, 0);//流步套接字 if (SOCKET_ERROR == sockClient) { printf("Socket() error:%d", WSAGetLastError()); //return 0; } //向伺服器發出連線請求 if (connect(sockClient, (struct sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET) { printf("Connect failed:%d", WSAGetLastError()); //return 0; } else { //先來一個把CString轉換成char*方法 /*int i; for (i = 0; i < m_user.GetLength(); i++) { user[i] = (char)(m_user.GetAt(i)); } user[i] = '\0'; i = 0; for (i = 0; i < m_pw.GetLength(); i++) { pw[i] = (char)(m_pw.GetAt(i)); } pw[i] = '\0';*/ wchar_t *ptr1, *ptr2; ptr1 = m_user.GetBuffer(m_user.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr1, -1, user, sizeof(user), NULL, NULL); m_user.ReleaseBuffer(); ptr2 = m_pw.GetBuffer(m_pw.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr2, -1, pw, sizeof(pw), NULL, NULL); m_pw.ReleaseBuffer(); recv(sockClient, buff, sizeof(buff), 0); //printf("%s\n", buff); int number; send(sockClient, "1", sizeof(user), 0);//傳送服務情況 //Sleep(1000); recv(sockClient, buff, sizeof(buff), 0); send(sockClient, user, sizeof(user), 0);//傳送使用者名稱 //cout << "send user failed"; //Sleep(1000); recv(sockClient, buff, sizeof(buff), 0); send(sockClient, pw, sizeof(pw), 0); //Sleep(1000); //cout << "send pw failed"; //recv(sockClient, buff, sizeof(buff), 0); memset(buff, 0, sizeof(buff)); recv(sockClient, buff, sizeof(buff), 0); if (strcmp(buff, "使用者名稱不存在") == 0) { //cout << "使用者名稱不存在"; AfxMessageBox(_T("使用者名稱不存在!")); //return ; } if (strcmp(buff, "密碼錯誤") == 0) { AfxMessageBox(_T("密碼錯誤!")); //return ; } if (strcmp(buff, "該使用者已存在") == 0) { AfxMessageBox(_T("該使用者已存在!")); //return ; } if (strcmp(buff, "密碼正確") == 0) { AfxMessageBox(_T("登入成功!")); GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE); success = true; } if (success) { //AfxBeginThread(recv_thd, NULL); //this->ShowWindows(SW_HIDE);//當前介面隱藏 //需要新增該C***Dlg.h標頭檔案,否則編譯通不過 Dlg.sockClient1 = sockClient; //Dlg.create(); //Dlg->Create(IDD_DIAGLOG_MAIN, GetDesktopWindow()); Dlg.DoModal(); /*pthread_t tids[10]; int res = pthread_create(&tids[0], NULL, recv1, (void*)&sockClient); if (res != 0) //建立執行緒成功返回0 { cout << "pthread_create error:error_code=" << res << endl; }*/ //recv1((void*)&sockClient); } //UpdateData(false); } //關閉套接字 //closesocket(sockClient); //WSACleanup(); } void Cconnent1Dlg::Update(CString s) { edit3.ReplaceSel(s); } /*void Cconnent1Dlg::OnBnClickedButton2() { // TODO: 在此新增控制元件通知處理程式程式碼 UpdateData(true); //num = (char)(.GetAt(0)); /*int i; for (i = 0; i < m_message.GetLength(); i++) { buff[i] = (char)(m_message.GetAt(i)); } buff[i] = '\0'; int i = 0; memset(nUser,0,sizeof(nUser)); for (i=0; i < suser.GetLength(); i++) { nUser[i] = (char)(suser.GetAt(i)); } nUser[i] = '\0'; //下面是將CString轉為char*的方法 wchar_t *ptr; ptr = m_message.GetBuffer(m_message.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr, -1, buff, sizeof(buff), NULL, NULL); m_message.ReleaseBuffer(); //char *buff1=(LPSTR)(LPCTSTR)m_message; //buff[0] = num; send(sockClient, nUser,sizeof(nUser), 0); Sleep(1); if (send(sockClient, buff, sizeof(buff), 0)<0) AfxMessageBox(_T("傳送失敗!")); //AfxMessageBox(_T("傳送成功!")); //} //memset(buff, 0, sizeof(buff)); //recv(sockClient,buff,sizeof(buff),0); }*/ void Cconnent1Dlg::OnBnClickedButton3() { // TODO: 在此新增控制元件通知處理程式程式碼 UpdateData(true); //載入套接字 WSADATA wsaData; char buff[10000]; memset(buff, 0, sizeof(buff));// if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Failed to load Winsock"); //return 0; } SOCKADDR_IN addrSrv; //服務端地址 addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(5099); addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //建立客戶端套接字 sockClient = socket(AF_INET, SOCK_STREAM, 0);//流步套接字 if (SOCKET_ERROR == sockClient) { printf("Socket() error:%d", WSAGetLastError()); //return 0; } //向伺服器發出連線請求 if (connect(sockClient, (struct sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET) { printf("Connect failed:%d", WSAGetLastError()); //return 0; } else { wchar_t *ptr1,*ptr2; ptr1 = m_user.GetBuffer(m_user.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr1, -1, user, sizeof(user), NULL, NULL); m_user.ReleaseBuffer(); ptr2 = m_pw.GetBuffer(m_pw.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr2, -1, pw, sizeof(pw), NULL, NULL); m_pw.ReleaseBuffer(); recv(sockClient, buff, sizeof(buff), 0); //傳送給伺服器註冊資訊 send(sockClient, "2", sizeof(user), 0);//傳送請求服務型別,為1表示登入,為2表示註冊 recv(sockClient,buff,sizeof(buff),0); send(sockClient, user, sizeof(user), 0);//傳送使用者名稱 recv(sockClient,buff,sizeof(buff),0); send(sockClient, pw, sizeof(pw), 0);//傳送密碼 //清空buff以接收伺服器傳來的訊息 memset(buff, 0, sizeof(buff)); recv(sockClient, buff, sizeof(buff), 0); if (strcmp(buff, "使用者名稱已存在") == 0) { AfxMessageBox(_T("使用者名稱已存在!")); } else if (strcmp(buff, "註冊已滿") == 0) { AfxMessageBox(_T("註冊使用者已滿!")); } else if (strcmp(buff, "註冊成功") == 0) { AfxMessageBox(_T("註冊成功!")); success = true; } } }
介面2:
// Cmessage.cpp: 實現檔案 // #include "stdafx.h" #include "connent1.h" #include "Cmessage.h" #include "afxdialogex.h" #include <WinSock2.h> #include <stdio.h> #include <pthread.h> #pragma comment(lib, "pthreadVC2.lib") #pragma comment(lib, "ws2_32.lib") #include<iostream> #include "connent1Dlg.h" using namespace std; // Cmessage 對話方塊 char buff1[1000]; char nUser1[1000]; SOCKET sockClient2; char num; /*void* recv2(void* args) { //SOCKET sockConn = *((SOCKET*)args); //HWND hWnd = *((HWND *)args); char recvBuf[10000]; //Cmessage * dlg = (Cmessage *)AfxGetApp()->GetMainWnd()->GetSafeHwnd(); //HWND hWnd = ::FindWindow(NULL, _T("Dialog")); //得到對話方塊的控制代碼 //Cmessage* pWnd = (Cmessage*)Cmessage::FromHandle(hWnd); //由控制代碼得到對話方塊的物件指標 //接收資料 if(hWnd==0) AfxMessageBox(_T("獲取當前控制代碼失敗")); while (hWnd!=0) { memset(recvBuf, 0, sizeof(recvBuf)); int nRecv = ::recv(sockClient2, recvBuf, sizeof(recvBuf), 0); if (nRecv > 0) { if (strcmp(recvBuf, "傳送的使用者名稱不存在") == 0)//檢測使用者名稱是否存在 { AfxMessageBox(_T("傳送的使用者名稱不存在!")); } else { CString a = CString(recvBuf) + _T("\n\r"); //AfxMessageBox(_T("接收成功")); //Dlg->m_show = a; //pWnd->m_show1=a; pWnd->Update1(a); //m_show = a; } } else break; } return recvBuf; }*/ UINT Cmessage::recv3(LPVOID p) { //SOCKET sockConn = *((SOCKET*)args); //HWND hWnd = *((HWND *)p); char recvBuf[10000]; Cmessage * dlg = (Cmessage *)p; //HWND hWnd = ::FindWindow(NULL, _T("Dialog")); //得到對話方塊的控制代碼 //Cmessage* pWnd = (Cmessage*)Cmessage::FromHandle(hWnd); //由控制代碼得到對話方塊的物件指標 //接收資料 //if (hWnd == 0) // AfxMessageBox(_T("獲取當前控制代碼失敗")); while (true) { memset(recvBuf, 0, sizeof(recvBuf)); int nRecv = ::recv(sockClient2, recvBuf, sizeof(recvBuf), 0); if (nRecv > 0) { if (strcmp(recvBuf, "傳送的使用者名稱不存在") == 0)//檢測使用者名稱是否存在 { AfxMessageBox(_T("傳送的使用者名稱不存在!")); } else if (strcmp(recvBuf, "使用者不線上") == 0)//檢測使用者名稱是否存在 { AfxMessageBox(_T("使用者不線上!")); } else { CString a = CString(recvBuf) + _T(" "); //AfxMessageBox(_T("接收成功")); //Dlg->m_show = a; //pWnd->m_show1=a; dlg->Update1(a); //m_show = a; } } else break; } //return recvBuf; return true; } IMPLEMENT_DYNAMIC(Cmessage, CDialogEx) Cmessage::Cmessage(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DIALOG1_MAIN, pParent) , userNumber(_T("")) , m_message1(_T("")) , m_show1(_T("")) { //Cconnent1Dlg *parent = (Cconnent1Dlg*)GetParent(); //sockClient = parent->sockClient; //recv1(sockClient); } Cmessage::~Cmessage() { } void Cmessage::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, userNumber); DDX_Text(pDX, IDC_EDIT2, m_message1); DDX_Text(pDX, IDC_EDIT4, m_show1); DDX_Control(pDX, IDC_EDIT4, edit4); } BEGIN_MESSAGE_MAP(Cmessage, CDialogEx) ON_EN_CHANGE(IDC_EDIT2, &Cmessage::OnEnChangeEdit2) ON_BN_CLICKED(IDC_BUTTON1, &Cmessage::OnBnClickedButton1) ON_EN_CHANGE(IDC_EDIT4, &Cmessage::OnEnChangeEdit4) ON_BN_CLICKED(IDC_BUTTON3, &Cmessage::OnBnClickedButton3) ON_BN_CLICKED(IDC_BUTTON2, &Cmessage::OnBnClickedButton2) END_MESSAGE_MAP() // Cmessage 訊息處理程式 void Cmessage::OnEnChangeEdit2() { // TODO: 如果該控制元件是 RICHEDIT 控制元件,它將不 // 傳送此通知,除非重寫 CDialogEx::OnInitDialog() // 函式並呼叫 CRichEditCtrl().SetEventMask(), // 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。 // TODO: 在此新增控制元件通知處理程式程式碼 } void Cmessage::Update1(CString s) { edit4.ReplaceSel(s); } void Cmessage::OnBnClickedButton1() { // TODO: 在此新增控制元件通知處理程式程式碼 // TODO: 在此新增控制元件通知處理程式程式碼 UpdateData(true); //num = (char)(.GetAt(0)); //實現CString到char*的轉化 wchar_t *ptr1; ptr1 = userNumber.GetBuffer(userNumber.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr1, -1, nUser1, sizeof(nUser1), NULL, NULL); userNumber.ReleaseBuffer(); wchar_t *ptr2; ptr2 = m_message1.GetBuffer(m_message1.GetLength() * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)ptr2, -1, buff1, sizeof(buff1), NULL, NULL); m_message1.ReleaseBuffer(); //buff[0] = num; send(sockClient2, nUser1, sizeof(nUser1), 0); Sleep(1); if (send(sockClient2, buff1, sizeof(buff1), 0)<0) AfxMessageBox(_T("傳送失敗!")); //AfxMessageBox(_T("傳送成功!")); //} //memset(buff, 0, sizeof(buff)); //recv(sockClient,buff,sizeof(buff),0); } void Cmessage::OnEnChangeEdit4() { // TODO: 如果該控制元件是 RICHEDIT 控制元件,它將不 // 傳送此通知,除非重寫 CDialogEx::OnInitDialog() // 函式並呼叫 CRichEditCtrl().SetEventMask(), // 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。 // TODO: 在此新增控制元件通知處理程式程式碼 } void Cmessage::OnBnClickedButton3() { Cconnent1Dlg *parent = (Cconnent1Dlg*)GetParent(); sockClient2 = parent->sockClient; AfxBeginThread(recv3, this); GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE); /*pthread_t tids[10]; int res = pthread_create(&tids[0], NULL, recv2, (void*)&this->m_hWnd); if (res != 0) //建立執行緒成功返回0 { cout << "pthread_create error:error_code=" << res << endl; } */ } void Cmessage::OnBnClickedButton2() { // TODO: 在此新增控制元件通知處理程式程式碼 char a[100] = "退出"; send(sockClient2, a, sizeof(a), 0); this->SendMessage(WM_CLOSE); AfxGetMainWnd()->SendMessage(WM_CLOSE); }
主要效果:
(主要實現後面補充。。。)