【MFC】网络通信(23)

Windows Sockets 规范是 Windows 平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克利加利福尼亚大学的 BSD UNIX Sockets 的实现。

Socket 套接字分为两种类型:数据报 socket 和数据流 socket。

数据报套接字,即无连接套接字,不保证传输的可靠性,比如视频通信、时钟同步、与服务器的“心跳”同步等应用场景。

数据流套接字是基于显示连接的套接字,提供没有记录边界的双向字节数据流,具有可靠的发送顺序,适用大量数据且可靠性要求高的传输。

CSocket实现数据流网络通信

步骤:

1、创建服务器通信程序: 

 在高级功能中勾选Widows套接字,否则需要手动包含套接字的头文件

#include <afxsock.h>
并且在应用程序类的InitInsatnce函数中初始化套接字:

BOOL CSockServerApp::InitInstance()
{
   .......
	CWinApp::InitInstance();

	if (!AfxSocketInit())  //手动添加初始化套接字
	{
		
		return FALSE;
	}
   ......
}

2、与服务器一样创建客户端程序(略),其中可以把两个项目都方在同一个解决方案里,如:

 

3、分别给服务器和客户端添加CSocket的派生类

利用类向导,添加虚函数 OnReceive 用于测试服务器发送数据给客户端

 

自动生成的代码 头文件:

#pragma once

// CClientSocket 命令目标

class CClientSocket : public CSocket
{
public:
	CClientSocket();
	virtual ~CClientSocket();
	virtual void OnReceive(int nErrorCode);
};

源文件:

// ClientSocket.cpp : 实现文件
//

#include "stdafx.h"
#include "TestSockClient.h"
#include "ClientSocket.h"


// CClientSocket

CClientSocket::CClientSocket()
{
}

CClientSocket::~CClientSocket()
{
}


// CClientSocket 成员函数


void CClientSocket::OnReceive(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类

	CSocket::OnReceive(nErrorCode);
}

同样的方法创建服务器的套接字,不同之处,比客户端多添加一个OnAccept的虚函数:

头文件:

#pragma once

// CServerSocket 命令目标

class CServerSocket : public CSocket
{
public:
	CServerSocket();
	virtual ~CServerSocket();
	virtual void OnReceive(int nErrorCode);
	virtual void OnAccept(int nErrorCode);
};

源文件:

// ServerSocket.cpp : 实现文件
//

#include "stdafx.h"
#include "TestSockServer.h"
#include "ServerSocket.h"


// CServerSocket

CServerSocket::CServerSocket()
{
}

CServerSocket::~CServerSocket()
{
}


// CServerSocket 成员函数


void CServerSocket::OnReceive(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类	
	CSocket::OnReceive(nErrorCode);
}


void CServerSocket::OnAccept(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类	
	CSocket::OnAccept(nErrorCode);
}

4、网络通信的流程其实很简单:

服务端:创建套接字-》侦听         侦听套接字

客户端:创建套接字-》连接服务器-》服务端侦听套接字获取连接事件(OnAccept)

服务端处理连接事件:创建一个 通信套接字 与客户端进行网络通信 ,也就是说服务端有一个侦听套接字和可能多个通信套接字。 

网络通信:客户端发送消息(Send),服务端中负责与客户端通信的套接字(OnReceive),通过Receive函数获取消息内容,完成通信。

创建套接字:

CServerSocket s;  //应该定义在主窗口类中

//创建套接字和侦听可以放在对话框的  OnInitDialog  函数中
s.Create(8000);  // 8000是服务器的端口  第二个参数默认为流式套接字,第三个参数为IP,默认本机
s.Listen(5); // 侦听队列,超过等待连接数据会阻塞

客户端套接字完成创建即可,注意要绑定在服务器端口(8000)不同的端口上。

CClientSocket c;    //应该定义在主窗口类中

//创建套接字可以放在对话框的  OnInitDialog  函数中
c.Create(8001);

//连接和发送消息的功能可以放于按钮点击事件处理中

c.Connect("127.0.0.1",8000); // 连接到服务器 127.0.0.1 本机IP
char buff[256]="hello";  //测试数据
c.Send(buff,strlen(buff)); // 发送数据到服务器

服务端套接字 OnAccept 函数,侦听和与客户端通信的套接字可以使用同一个类

void CServerSocket::OnAccept(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类
	
	CServerSocket *p = new CServerSocket();
	this->Accept(*p);
	CSocket::OnAccept(nErrorCode);
}

new 一个通信套接字(不能为对象,局部对象会被销毁),与客户端进行连接。这是一种最简单的测试方法,有点类似“内存泄漏”----------new 在堆里,而定义的指针 p 是一个局部变量!

“内存泄漏”  : 服务端收到客户端信息时, OnReceive 会被调用,堆中的通信套接字又可以获取到了。

void CServerSocket::OnReceive(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类
	char buff[256];
	int size = this->Receive(buff,256);    
    // this 为服务端的通信套接字,又“冒”出来了
    //size为实际接受的数据
	buff[size]='\0';  //字符串结束符
	::AfxMessageBox(buff);
	CSocket::OnReceive(nErrorCode);
}

5、改进与提升方向

  • 使用多线程(窗口线程)与通信套接字绑定来实现网络通信,尤其是服务端。
  • CSocketFile 的Write 、Read  来代替 套接字 Send 和 Receive ,实现大数据的通信
  • “安全”数据报方式实现客户端的互连(不通过服务器转发)
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值