MFC局域网的winsocket编程

MFC局域网的winsocket编程

1.功能简介

客户端:

  • 与服务器建立连接
  • 发送消息到服务器
  • 断开与服务器的连接

服务器端:

  • 接受客户端的请求
  • 将某个客户端发来的消息广播到其他的在线客户端
2.winsocket模块

1.服务器端和客户端收发数据前准备工作:
     服务器端应用程序(创建套接字socket,绑定bind,监听listen,接受用户请求accept)
     客户端应用程序(根据服务器应用程序所在IP和PORT创建套接字socket,连接conn)
2.收发数据操作:
     接收数据recv(SOCKET Socket, char *recvbuf, int recvbuflen, 0);
     发送数据recv(SOCKET Socket, char *recvbuf, int recvbuflen, 0);
3.关闭连接:
     shutdown(SOCKET Socket, SD_SEND);
4.删除套接字:
     closesocket(SOCKET Socket);
5.WSAAsyncSelect模型,通知套接字端口有请求事件发生,用于更新数据
  WSAAsyncSelect(SOCKET Socket,m_hWnd,WM_SOCKET, FD_READ|FD_WRITE|FD_ACCEPT);
  WSAAsyncSelect(套接字,窗口句柄,自定义窗口消息ID,事件)
6.自定义窗口消息:
     1.#define WM_SOCKET WM_USER+11 使用宏定义消息ID
     2.afx_msg LRESULT OnSocket(WPARAM w, LPARAM l); 在CServerMFCDlg.h中声明消息响应函数
     3.将消息映射到处理函数

BEGIN_MESSAGE_MAP(CServerMFCDlg, CDialog)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_LISTENBUTTON, &CServerMFCDlg::OnClickedListenbutton)
ON_MESSAGE(WM_SOCKET,OnSocket)  在CServerMFCDlg.cpp中加入这句,将消息映射到处理函数
END_MESSAGE_MAP()

3.MFC界面设计模块:

服务器端:

控件 ID 变量 说明
ListBox(消息栏) IDC_MESSAGELIST m_MessageList 类别为Control控件
ListBox(在线用户) IDC_ONLINELIST m_OnlineList 类别为Value,类型为CString
EditBox(IP) IDC_IPEDIT m_ip 类别为Value,类型为CString
EditBox(Port) IDC_PORTEDIT m_port 类别为Value,类型为CString
Button(监听按钮) IDC_LISTENBUTTON 类向导添加单击事件

客户端:

控件 ID 变量 说明
ListBox(消息栏) IDC_MESSAGELIST m_MessageList 类别为Control控件
EditBox(消息发送栏) IDC_SENDEDIT m_SendMessage 类别为Value,类型为CString
EditBox(IP) IDC_IPEDIT m_ip 类别为Value,类型为CString
EditBox(Port) IDC_PORTEDIT m_port 类别为Value,类型为CString
Button(发送按钮) IDC_SENDBUTTON 类向导添加单击事件
Button(连接按钮) IDC_CONNBUTTON 类向导添加单击事件
Button(断开按钮) IDC_CLOSEBUTTON 类向导添加单击事件

4.代码实现

扫描二维码关注公众号,回复: 2303903 查看本文章
// ServerMFCDlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include "afxcmn.h"
#define CLIEN_MAXNUM 12

// CServerMFCDlg 对话框
class CServerMFCDlg : public CDialog
{
// 构造
public:
    CServerMFCDlg(CWnd* pParent = NULL);    // 标准构造函数

// 对话框数据
    enum { IDD = IDD_SERVERMFC_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg LRESULT OnSocket(WPARAM w, LPARAM l);
    DECLARE_MESSAGE_MAP()
public:
    CListBox m_MessageList;
    CString m_ip;
    CString m_port;
private:
    char* serverName;
    char* serverPort;
    SOCKET ClientSocketList[CLIEN_MAXNUM];
    char* ClientIPList[CLIEN_MAXNUM];
    u_short ClientPortList[CLIEN_MAXNUM];
    int cursor;
    SOCKET ListenSocket;
    WSADATA wsaData;
    SOCKET ClientSocket;
    void open();
public:
    afx_msg void OnClickedListenbutton();

    CListBox m_OnlineList;
};
// ServerMFCDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "ServerMFC.h"
#include "ServerMFCDlg.h"
#include "afxdialogex.h"

#include "WinSock2.h"
#include "windows.h"
#include "ws2tcpip.h"
#define CLIEN_MAXNUM 12
#define DEFAULT_BUFLEN 1024

#define WM_SOCKET WM_USER+11

#pragma comment(lib,"Ws2_32.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CServerMFCDlg 对话框



CServerMFCDlg::CServerMFCDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CServerMFCDlg::IDD, pParent)
    , m_ip(_T(""))
    , m_port(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CServerMFCDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_MESSAGELIST, m_MessageList);
    DDX_Text(pDX, IDC_IPEDIT, m_ip);
    DDX_Text(pDX, IDC_PORTEDIT, m_port);

    DDX_Control(pDX, IDC_LIST1, m_OnlineList);
}

BEGIN_MESSAGE_MAP(CServerMFCDlg, CDialog)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_LISTENBUTTON, &CServerMFCDlg::OnClickedListenbutton)
    ON_MESSAGE(WM_SOCKET,OnSocket)
END_MESSAGE_MAP()


// CServerMFCDlg 消息处理程序

BOOL CServerMFCDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码
    cursor =  0;
    for (int i=0; i<CLIEN_MAXNUM;i++)
        ClientSocketList[i] = NULL;
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CServerMFCDlg::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
    {
        CDialog::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CServerMFCDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}
void CServerMFCDlg::open()
{
    struct addrinfo *result;
    struct addrinfo hints;
    ListenSocket = INVALID_SOCKET;
    ClientSocket = INVALID_SOCKET;
    int iResult = 0;
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (0 != iResult) 
        MessageBoxA(NULL,"WSAStartup failed with error","error",MB_OK);
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and por
    iResult = getaddrinfo(serverName, serverPort, &hints, &result);
    if ( 0 != iResult) {
        MessageBoxA(NULL,"getaddrinfo failed with error","error",MB_OK);
        WSACleanup();
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        MessageBoxA(NULL,"socket failed with error","error",MB_OK);
        freeaddrinfo(result);
        WSACleanup();
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        MessageBoxA(NULL,"bind failed with error","error",MB_OK);
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, CLIEN_MAXNUM);
    if (iResult == SOCKET_ERROR) {
        MessageBoxA(NULL,"listen failed with error","error",MB_OK);
        closesocket(ListenSocket);
        WSACleanup();
    }
}

void CServerMFCDlg::OnClickedListenbutton()
{
    //first we initialize the port and the ip address
    //transmit the value of the Control to member
    UpdateData(TRUE);
    //convert to char* from CString
    USES_CONVERSION;
    serverName = T2A(m_ip.GetBuffer(0));
    m_ip.ReleaseBuffer();
    serverPort = T2A(m_port.GetBuffer(0));
    m_port.ReleaseBuffer();

    //start listen the port
    open();
    //output the successful information
    CString openSuccessInfo;
    openSuccessInfo.Format(_T("主机%s监听端口%s......"),m_ip.GetBuffer(0),m_port.GetBuffer(0));
    m_MessageList.AddString(openSuccessInfo);
    //transmit the value of member to the Control
    UpdateData(FALSE);
    WSAAsyncSelect(ListenSocket,m_hWnd,WM_SOCKET, FD_READ|FD_WRITE|FD_ACCEPT);
}
LRESULT CServerMFCDlg::OnSocket(WPARAM  w, LPARAM l)
{
    switch(l)
    {
        case FD_ACCEPT:
        {
            sockaddr_in m_client;
            int sz;
            sz = sizeof(sockaddr_in);
            ClientSocket = accept(ListenSocket, (sockaddr*)&m_client, &sz);
            if(ClientSocket == INVALID_SOCKET)
            {
               closesocket(ListenSocket);
               WSACleanup();
            }
            ClientSocketList[cursor] = ClientSocket;
            char* clientIP = inet_ntoa(m_client.sin_addr);
            u_short clientPort = ntohs(m_client.sin_port);
            ClientIPList[cursor] = clientIP;
            ClientPortList[cursor] = clientPort;
            cursor++;
            CString receivedInfo;
            receivedInfo.Format(_T("%s/%d 进入聊天室......"), CStringW(clientIP),clientPort);
            m_MessageList.AddString(receivedInfo);
            //add to online client list
            CString clientInfo;
            clientInfo.Format(_T("%s:%d"), CStringW(clientIP),clientPort);
            m_OnlineList.AddString(clientInfo);
            UpdateData(FALSE);
            USES_CONVERSION;
            char *buf = T2A(receivedInfo.GetBuffer(0));
            int len = CStringA(receivedInfo).GetLength();
            for(int i=0; i<cursor; i++)
                send(ClientSocketList[i],buf,len,0);
        }
            break;
        case FD_READ:
        {
            char* buffer = new char[DEFAULT_BUFLEN];
            int res = -1;
            int curClient;
            for (int i=0; i<CLIEN_MAXNUM;i++)
            {
                res = recv(ClientSocketList[i], buffer, DEFAULT_BUFLEN,0);
                if(res > 0)
                {
                    curClient = i;
                    break;
                }
            }
            buffer[res] = '\0';
            CString receivedStr;
            if(res > 0)
            {
                receivedStr.Format(_T("%s/%d:%s"), CStringW(ClientIPList[curClient]),ClientPortList[curClient],CStringW(buffer));
                m_MessageList.AddString(receivedStr);
                //transmit the value of member to the Control
                UpdateData(FALSE);
            }
            USES_CONVERSION;
            char *buf = T2A(receivedStr.GetBuffer(0));
            int len = CStringA(receivedStr).GetLength();
            for(int i=0; i<cursor; i++)
                send(ClientSocketList[i],buf,len,0);
        }
            break;
    }
    return 1;
}
// ClientMFCDlg.h : 头文件
//

#pragma once
#include "afxwin.h"


// CClientMFCDlg 对话框
class CClientMFCDlg : public CDialog
{
// 构造
public:
    CClientMFCDlg(CWnd* pParent = NULL);    // 标准构造函数

// 对话框数据
    enum { IDD = IDD_CLIENTMFC_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();
    afx_msg LRESULT OnSocket(WPARAM w, LPARAM l);
    DECLARE_MESSAGE_MAP()

public:
    CString m_ip;
    CString m_port;
    CString m_SendMessage;
    CListBox m_MessageList;

private:
    char* serverName;
    char* serverPort;
    WSADATA wsaData;
    SOCKET ConnectSocket;
    void conn();
    void close();
public:

    afx_msg void OnClickedConnbutton();
    afx_msg void OnClickedSnedbutton();
    afx_msg void OnBnClickedDisconnbutton();
};
// ClientMFCDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "ClientMFC.h"
#include "ClientMFCDlg.h"
#include "afxdialogex.h"

#include "windows.h"
#include "winsock2.h"
#include "ws2tcpip.h"
#define DEFAULT_BUFLEN 1024
#define WM_SOCKET WM_USER+11

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CClientMFCDlg 对话框



CClientMFCDlg::CClientMFCDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CClientMFCDlg::IDD, pParent)
    , m_ip(_T(""))
    , m_port(_T(""))
    , m_SendMessage(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CClientMFCDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT1, m_ip);
    DDX_Text(pDX, IDC_EDIT2, m_port);
    DDX_Text(pDX, IDC_EDIT4, m_SendMessage);
    DDX_Control(pDX, IDC_LIST1, m_MessageList);
}

BEGIN_MESSAGE_MAP(CClientMFCDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_CONNBUTTON, &CClientMFCDlg::OnClickedConnbutton)
    ON_BN_CLICKED(IDC_SNEDBUTTON, &CClientMFCDlg::OnClickedSnedbutton)
    ON_MESSAGE(WM_SOCKET,OnSocket)
    ON_BN_CLICKED(IDC_DISCONNBUTTON, &CClientMFCDlg::OnBnClickedDisconnbutton)
END_MESSAGE_MAP()


// CClientMFCDlg 消息处理程序

BOOL CClientMFCDlg::OnInitDialog()
{
    CDialog::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: 在此添加额外的初始化代码

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CClientMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CClientMFCDlg::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
    {
        CDialog::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CClientMFCDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

void CClientMFCDlg::conn()
{
    ConnectSocket = INVALID_SOCKET;
    struct addrinfo *ptr,*result = NULL;
    struct addrinfo hints;
    int iResult = 0;
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) 
        MessageBoxA(NULL,"WSAStartup failed with error","error",MB_OK);
    /*hostName = new char[256];
    gethostname(hostName,sizeof(hostName));*/
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(serverName, serverPort, &hints, &result);
    if ( 0 != iResult) {
        MessageBoxA(NULL,"getaddrinfo failed with error","error",MB_OK);
        WSACleanup();
    }
     // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {

            WSACleanup();
        }

        // Connect to server.
       iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }
    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        MessageBoxA(NULL,"socket failed with error","error",MB_OK);
        WSACleanup();
    }
}


void CClientMFCDlg::close()
{
    int iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        MessageBoxA(NULL,"shutdown failed with error","error",MB_OK);
        closesocket(ConnectSocket);
        WSACleanup();
    }
    closesocket(ConnectSocket);
    WSACleanup();
}




void CClientMFCDlg::OnClickedConnbutton()
{
    UpdateData(TRUE);
    //convert to char* from CString
    USES_CONVERSION;
    serverName = T2A(m_ip.GetBuffer(0));
    m_ip.ReleaseBuffer();
    serverPort = T2A(m_port.GetBuffer(0));
    m_port.ReleaseBuffer();
    conn();
    WSAAsyncSelect(ConnectSocket,m_hWnd,WM_SOCKET, FD_READ);
}


void CClientMFCDlg::OnClickedSnedbutton()
{
    CString sendInfo;
    UpdateData(TRUE);
    sendInfo.Format(_T("%s"),CStringW(m_SendMessage.GetBuffer(0)));
    int len = CStringA(sendInfo).GetLength();
    USES_CONVERSION;
    char *buf = T2A(sendInfo.GetBuffer(0));
    int iSendResult = send(ConnectSocket, buf, len, 0);
    if (iSendResult == SOCKET_ERROR) {
            MessageBoxA(NULL,"send failed with error","error",MB_OK);
            closesocket(ConnectSocket);
            WSACleanup();
     }

}

LRESULT CClientMFCDlg::OnSocket(WPARAM  w, LPARAM l)
{
    SOCKET s = (SOCKET)w;
    switch(l)
    {
        case FD_READ:
            char* buffer = new char[DEFAULT_BUFLEN];
            int res = recv(s,buffer,DEFAULT_BUFLEN,0);
            if(res > 0)
            {
                CString receivedStr;
                buffer[res] = '\0';
                receivedStr.Format(_T("%s"),CStringW(buffer));
                m_MessageList.AddString(receivedStr);
                //transmit the value of member to the Control
                UpdateData(FALSE);
            }
            break;
    }
    return 1;
}


void CClientMFCDlg::OnBnClickedDisconnbutton()
{
    close();
}
5.问题与解决方法

1.char*类型的变量转换成CString类型变量
     char *buffer = new char[1024];
     CString receivedStr;
     receivedStr.Format(_T(“%s”),CStringW(buffer));
     写成receivedStr.Format(_T(“%s”),buffer);会出现乱码,应用CStringW进行转换
2.CString类型的变量转换成char*类型变量
     CString sendInfo;
     USES_CONVERSION;
     char *buf = T2A(sendInfo.GetBuffer(0));
2.接收数据时出现多余的数据
     char* buffer = new char[DEFAULT_BUFLEN];
     int res = recv(s,buffer,DEFAULT_BUFLEN,0);
     buffer[res] = ‘\0’;//res为接收到的字节数,这里用\0表示字符串结束
3.在服务器端获得客户端的IP和端口
     sockaddr_in m_client;
     int sz;
     sz = sizeof(sockaddr_in);
     ClientSocket =      accept(ListenSocket, (sockaddr*)&m_client, &sz);
     char* clientIP = inet_ntoa(m_client.sin_addr);//获得主机IP
     u_short clientPort = ntohs(m_client.sin_port);//获得主机端口号
4.send发送数据时总是不能发送正确字节数数据
     CString::GetLength()获得正确的字节数
     CString str(“你好ab”);
     str.GetLength();//结果为4,当发送数据时,只能发送”你好”到另一端
     CStringA(str).GetLength();//结果为6,正确
5.MFC空间添加变量更新数据
     UpdateData(TRUE);//将控件值赋值给控件变量
     UpdateData(FALSE);//将控件变量同步到控件中

6.运行截图

服务器监听端口:

cmd中netstat -ano 命令可以看出端口9080被监听
这里写图片描述
一个客户端(端口号为1135)请求连接服务器:
这里写图片描述
建立连接后修改了连接状态,由LISTENING变为ESTABLISHED
这里写图片描述
另一个客户端请求连接服务器(端口号为1135)
这里写图片描述
发送消息可以广播到其它的客户端
这里写图片描述
最后其中一个客户端(端口号为1135)断开连接
这里写图片描述

7.源代码

https://github.com/15045120/ClientMFC
https://github.com/15045120/ServerMFC

8.参考文献

[1]谢希仁.计算机网络[M] (第7版).电子工业出版社,2007.
[2]户根勤.网络是怎样连接的[M].人民邮电出版社,2017.1.
[3]徐斌.MFC小型局域网聊天室的实现[D].西南大学网络与继续教育学院专升本论文,2014:5-10.
[4]VC初学者.MFC自定义消息[OL].(2018-05-28).https://www.cnblogs.com/xydblog/archive/2014/02/25/3566266.html.
[5]u010306834.关于VS2010 CString.Format()之后乱码的问题[OL].(2018-05-28)https://blog.csdn.net/u010306834/article/details/39495305.
[6]beitcoder.CString 和 char * 的相互转换[OL].(2018-05-28)https://blog.csdn.net/beitcoder/article/details/1538154.
[7]weiyuefei.accept成功后获取客户端ip[OL].(2018-05-28)https://blog.csdn.net/weiyuefei/article/details/52956769.
[8]郑文亮.CString::GetLength()获得字节数的正确方法[OL].(2018-05-28)https://www.cnblogs.com/zhwl/archive/2012/11/09/2762962.html.
[9]Microsoft.Getting Started with Winsock[OL].(2018-05-28)https://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx

猜你喜欢

转载自blog.csdn.net/qq_36336003/article/details/80487927
今日推荐