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_MESSAGELISTm_MessageList类别为Control控件
ListBox(在线用户)IDC_ONLINELISTm_OnlineList类别为Value,类型为CString
EditBox(IP)IDC_IPEDITm_ip类别为Value,类型为CString
EditBox(Port)IDC_PORTEDITm_port类别为Value,类型为CString
Button(监听按钮)IDC_LISTENBUTTON类向导添加单击事件
客户端:
控件变量ID说明
ListBox(消息栏)IDC_MESSAGELISTm_MessageList类别为Control控件
EditBox(消息发送栏)IDC_SENDEDITm_SendMessage类别为Value,类型为CString
EditBox(IP)IDC_IPEDITm_ip类别为Value,类型为CString
EditBox(Port)IDC_PORTEDITm_port类别为Value,类型为CString
Button(发送按钮)IDC_SENDBUTTON类向导添加单击事件
Button(连接按钮)IDC_CONNBUTTON类向导添加单击事件
Button(断开按钮)IDC_CLOSEBUTTON类向导添加单击事件

4.问题与解决方法

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);//将控件变量同步到控件中

5.运行截图

服务器监听端口:

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

6.源代码

https://github.com/15045120/winsocket-usage/tree/master/ClientMFC
https://github.com/15045120/winsocket-usage/tree/master/ServerMFC

7.参考文献

[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

已标记关键词 清除标记
相关推荐
环境:Windows XP SP 3、 VC++ 6.0、 Windows Server 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0 IDE打开.dws文件 2、点击“!”按钮运行程序 3、如果一切正常会出现一个对话框,然后选择下拉框中“服务端”启动服务器进程--接着点击“监听”按钮 4、然后再点击“!”按钮运行客户端进程 5、如果一切正常,那么选择下拉框中“客户端”启动客户端进程--接着点击“连接”按钮,让客户端连接到socket服务器 6、在客户端“消息”栏中输入信息,然后点击“发送”按钮 7、点击服务器端进程,应该可以看见客户端发送过来消息,然后可以在“消息”栏中输入响应信息,然后点击“发送”按钮,此时会在客户端进程中看服务器端进程响应信息 该示例是实现了一个客户端对象对应一个服务端对象socket网络编程--最简单VC++网络编程示例。该示使用主要是自定义一个类--它继承MFC库中CAsyncSocket类,然后重写OnAccept, OnSend, OnReceive和OnClose方法来实现一对一VC++socket网络编程。注意:自定义类关联应用向导生成对话框类,需要在头文件中书写语句“class CHelloSocketDlg;”,并且在.cpp文件中写入语句“#include "HelloSocketDlg.h";”,否则编译不会通过! 本示例使用Dialog模式UI是为方便说明socket编程,在对话框类OnInitDialog方法有初始化成员变量注释说明,在自定义类中注释非常详细。本人觉得MFC使用异步通信类CAsyncSocket实现Java中ServerSocket类和Socket编程效果,是非常牛!(虽然本人认为它还封装得不够OO--因为它封装得让使用者觉得“很傻很天真”)。
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页