都說這個很簡單,我真的是找了好久然後自己也寫了好久的程序終於,把兩個程序調通了,原理我就不介紹了,大家一搜全是的,在這裏主要是爲了給自己做個記錄也爲了讓廣大的同行們節約時間,不用自己再調代碼。
(1)首先,建立兩個基於對話框的項目,分別命名爲cFile,sFile,注意勾選Windows套接字選項:
(2)服務端界面如下:插入一個Listbox Control,改ID爲IDC_LIST1,添加變量m_listwords;插入一個Edit Control,ID爲IDC_EDIT1,插入一個Button Control,ID爲IDC_BtnSend,然後添加代碼。
(3)服務端程序:
// sFileDlg.h : 頭文件
//
#pragma once
#include "afxwin.h"
static CString IP; //定義爲全局變量
void CString2Char(CString str, char ch[]); //此函數爲字符格式轉換函數
// CsFileDlg 對話框
class CsFileDlg : public CDialogEx
{
// 構造
public:
CsFileDlg(CWnd* pParent = NULL); // 標準構造函數
// 對話框數據
enum { IDD = IDD_SFILE_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
HICON m_hIcon;
// 生成的消息映射函數
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CListBox m_listwords;
void update(CString s);
private:
CEdit* show_edit;
CEdit* send_edit;
public:
afx_msg void OnBnClickedBtnsend();
};
// sFileDlg.cpp : 實現文件
//
#include "stdafx.h"
#include "sFile.h"
#include "sFileDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
SOCKET listen_sock;
SOCKET sock;
UINT server_thd(LPVOID p);
// 用於應用程序“關於”菜單項的 CAboutDlg 對話框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話框數據
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CsFileDlg 對話框
CsFileDlg::CsFileDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CsFileDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CsFileDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_listwords);
}
BEGIN_MESSAGE_MAP(CsFileDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BtnSend, &CsFileDlg::OnBnClickedBtnsend)
END_MESSAGE_MAP()
// CsFileDlg 消息處理程序
BOOL CsFileDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”菜單項添加到系統菜單中。
// IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
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: 在此添加額外的初始化代碼
send_edit = (CEdit *)GetDlgItem(IDC_EDIT1);
send_edit->SetFocus();
char name[128];
hostent* pHost;
gethostname(name, 128);//獲得主機名
pHost = gethostbyname(name);//獲得主機結構
IP = inet_ntoa(*(in_addr *)pHost->h_addr);
update(_T("本服務器IP地址:") + IP);
AfxBeginThread(server_thd, NULL);//創建線程
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
void CsFileDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪製該圖標。 對於使用文檔/視圖模型的 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);
}
void CsFileDlg::update(CString s)
{
m_listwords.AddString(s);
}
void CString2Char(CString str, char ch[])//此函數就是字符轉換函數的實現代碼
{
int i;
char *tmpch;
int wLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);//得到Char的長度
tmpch = new char[wLen + 1]; //分配變量的地址大小
WideCharToMultiByte(CP_ACP, 0, str, -1, tmpch, wLen, NULL, NULL); //將CString轉換成char*
for (i = 0; tmpch[i] != '\0'; i++) ch[i] = tmpch[i];
ch[i] = '\0';
}
UINT server_thd(LPVOID p)//線程要調用的函數
{
WSADATA wsaData;
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
// WSAStartup(0x0202, &wsaData);
SOCKADDR_IN local_addr;
SOCKADDR_IN client_addr;
int iaddrSize = sizeof(SOCKADDR_IN);
int res;
char msg[1024];
CsFileDlg * dlg = (CsFileDlg *)AfxGetApp()->GetMainWnd();
char ch_ip[20];
CString2Char(IP, ch_ip);//注意!這裏調用了字符格式轉換函數,此函數功能:CString類型轉換爲Char類型,實現代碼在後面添加
//local_addr.sin_addr.s_addr = htonl(INADDR_ANY);//獲取任意IP地址
local_addr.sin_addr.s_addr = inet_addr(ch_ip);
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(8888);
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)//創建套接字
{
dlg->update(_T("創建監聽失敗"));
}
if (bind(listen_sock, (struct sockaddr*) &local_addr, sizeof(SOCKADDR_IN)))//綁定套接字
{
dlg->update(_T("綁定錯誤"));
}
listen(listen_sock, 1);
if ((sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)//接收套接字
{
dlg->update(_T("accept 失敗"));
}
else
{
CString port;
port.Format(_T("%d"), int(ntohs(client_addr.sin_port)));
dlg->update(_T("已連接客戶端:") + CString(inet_ntoa(client_addr.sin_addr)) + " 端口:" + port);
}
////////////接收數據
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) == -1)
{
dlg->update(_T("失去客戶端的連接"));
break;
}
else
{
msg[res] = '\0';
dlg->update(_T("client:") + CString(msg));
}
}
return 0;
}
void CsFileDlg::OnBnClickedBtnsend()
{
// TODO: 在此添加控件通知處理程序代碼
CString s;
char msg[1024];
send_edit->GetWindowTextW(s);
CString2Char(s, msg); //注意!這裏調用了字符格式轉換函數,此函數功能:CString類型轉換爲Char類型,實現代碼後面添加
if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
{
show_edit->ReplaceSel(_T("發送失敗"));
m_listwords.SetWindowTextW(_T("發送失敗"));
}
else if (s == "")
{
MessageBox(_T("請輸入信息"));
}
else
{
s = msg;
//update(s);//消息上屏,清空輸入,並重獲焦點
//show_edit->ReplaceSel(_T("server:") + s);//消息上屏,清空輸入,並重獲焦點
m_listwords.AddString(_T("server:") + s);
send_edit->SetWindowText(_T(""));
m_listwords.SetFocus();
}
}
(4)客戶端界面如下:添加一個IP Control,ID爲IDC_IPADDRESS2,添加變量m_ip;添加一個Listbox Control,ID爲IDC_LIST1,添加變量m_listwords;添加一個Edit Control,ID爲IDC_EDIT1,添加變量m_message;添加兩個按鈕發送和連接,改ID爲IDC_BtnSend和IDC_BtnConnect。
(5)客戶端程序:
// cFileDlg.h : 頭文件
//
#pragma once
#include "afxwin.h"
#include "afxcmn.h"
//void CString2Char(CString str, char ch[]);
// CcFileDlg 對話框
class CcFileDlg : public CDialogEx
{
// 構造
public:
CcFileDlg(CWnd* pParent = NULL); // 標準構造函數
// 對話框數據
enum { IDD = IDD_CFILE_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
HICON m_hIcon;
// 生成的消息映射函數
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CListBox m_listwords;
CIPAddressCtrl m_ip;
void update(CString s);
private:
CEdit* send_edit;
CEdit* show_edit;
CEdit* ip_edit;
public:
afx_msg void OnBnClickedBtnconnect();
afx_msg void OnBnClickedBtnsend();
};
// cFileDlg.cpp : 實現文件
//
#include "stdafx.h"
#include "cFile.h"
#include "cFileDlg.h"
#include "afxdialogex.h"
#include <winsock2.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
SOCKET sock;
UINT server_thd(LPVOID p);
// 用於應用程序“關於”菜單項的 CAboutDlg 對話框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話框數據
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CcFileDlg 對話框
CcFileDlg::CcFileDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CcFileDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CcFileDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_listwords);
DDX_Control(pDX, IDC_IPADDRESS2, m_ip);
}
BEGIN_MESSAGE_MAP(CcFileDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BtnConnect, &CcFileDlg::OnBnClickedBtnconnect)
ON_BN_CLICKED(IDC_BtnSend, &CcFileDlg::OnBnClickedBtnsend)
END_MESSAGE_MAP()
// CcFileDlg 消息處理程序
BOOL CcFileDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”菜單項添加到系統菜單中。
// IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
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: 在此添加額外的初始化代碼
send_edit = (CEdit *)GetDlgItem(IDC_EDIT1);
show_edit = (CEdit *)GetDlgItem(IDC_LIST1);
ip_edit = (CEdit *)GetDlgItem(IDC_IPADDRESS2);
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
void CcFileDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪製該圖標。 對於使用文檔/視圖模型的 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)
{
m_listwords.AddString(s);
}
UINT recv_thd(LPVOID p)
{
int res;
char msg[1024];
CcFileDlg * dlg = (CcFileDlg *)AfxGetApp()->GetMainWnd();
////////////接收數據
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) == -1)//接收服務器的數據
{
dlg->update(_T("失去連接"));
break;
}
else
{
msg[res] = '\0';
dlg->update(_T("server:") + CString(msg));
}
}
//closesocket(sock);
return 0;
}
void CcFileDlg::OnBnClickedBtnconnect()
{
// TODO: 在此添加控件通知處理程序代碼
WSADATA wsaData;
SOCKADDR_IN server_addr;
memset(&server_addr, 0, sizeof(server_addr));
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
update(_T("create socket error !!!"));
}
BYTE nArrIP[4];
m_ip.GetAddress(nArrIP[0], nArrIP[1], nArrIP[2], nArrIP[3]);
CString str;
str.Format(_T("%d.%d.%d.%d"), nArrIP[0], nArrIP[1], nArrIP[2], nArrIP[3]);
ip_edit->SetWindowText(str);
char cp[50];
strncpy(cp, (LPCTSTR)str, sizeof(cp));
server_addr.sin_addr.s_addr = inet_addr(cp);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
bind(sock, (SOCKADDR*)&server_addr, sizeof(SOCKADDR));
if (connect(sock, (struct sockaddr *) &server_addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
update(_T("連接失敗"));
}
else
{
//show_edit->SetWindowText(_T(""));
update(_T("連接成功"));
//btnconnet->EnableWindow(FALSE);//按鈕變灰
AfxBeginThread(recv_thd, NULL);
}
}
void CcFileDlg::OnBnClickedBtnsend()
{
// TODO: 在此添加控件通知處理程序代碼
CString s;
char *msg;
send_edit->GetWindowText(s);
//CString2Char(s, msg);
//strncpy(msg, (LPCTSTR)s, sizeof(msg));
msg = s.GetBuffer(s.GetLength());
if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
{
update(_T("發送失敗"));
}
else if (s == "")
{
MessageBox(_T("請輸入信息"));
}
else
{
s = msg;
update(_T("client:") + s);//消息上屏,清空輸入,並重獲焦點
send_edit->SetWindowText(_T(""));
send_edit->SetFocus();
}
}
(6)結果: