飞秋跨网段通信

北飞 2009-07-28 09:05:00
关于飞秋的跨网段通信的问题,昨天试了下如果两台计算机都在路由器后面的话,就是说这两台电脑都是通过路由器上公网,而每个路由器下面又有好多台计算机,我从“加其他网段好友”这个功能里加了相应的路由器的IP就可以加这个下面的在线好友了,它怎么能加为好友,又怎么能知道信息该发给谁呢,这是怎么实现的呢,哪位大哥能给解释下它的原理呢,非常感谢?
...全文
4973 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
天天程序员 2012-09-28
  • 打赏
  • 举报
回复
跨网段通信还需要交换机的支持,需要配置一下,一般默认情况下(以cisco 3650为例),交换机的组播转发是关闭。此种情况下你的程序编出花样来也无法跨网段通信。
龍月 2009-07-28
  • 打赏
  • 举报
回复
局域网通讯的难题,跨网段通讯方法

多播

局域网的资源丰富,使用Windows共享机制可以很方便的访问大家的共享文件。但你能搜索到和你不同网段的资源么。不行。那么使用其他的软件(非跨网段专用通讯软件)能相互通讯么?不能。

这是为什么呢?因为局域网中也使用TCP/IP协议,而TCP/IP协议中常用的基础协议TCP和UDP都使用子网掩码这个东东。所以如果你们的子网不是相互包含,那么你们通讯时所发送的数据包将被无情的丢弃。

那我用广播通讯不行么? 当然行啦,不过广播通信会增加其他非参与者的负荷。如果使用多播,嘿嘿。一切OK!

多播通讯编程难么? 我原来也以为很难,呵呵,现在我可不那么认为了,
下面是多播通讯类的代码。

//Multicast.c

#pragma once

// auth: YYcYY

// date: 2006-8-12

// copyright: All free

//定义收到数据时通知父窗口的消息编号:WM_MUC_RECEIVE_DATA

#define WM_MUC_RECEIVE_DATA (WM_USER + 1097)
#define MAX_MUC_PACKET_SIZE 1460
#define SEND_BUFF_COUNT 4
#define RECEIVE_BUFF_COUNT 32
#define MU_PORT 5201
#define MU_GROUP_IP "224.0.0.8"

const int PACKET_HEAD_SIZE = 20;


#define MSG_TYPE_ALLUSER 1
#define MSG_TYPE_ACK 2
#define MSG_TYPE_ONLINE 3
#define MSG_TYPE_PROXY_REQUEST 4 //特殊用途#define MSG_TYPE_ONEUSER 5

struct SPACKET
{
char used;
char nType;
long long time;
int nUnused;
char data[MAX_MUC_PACKET_SIZE-20];
};

// CMulticast 命令目标

class CMulticast : public CAsyncSocket
{
private:
CWnd * m_pParent;

SOCKADDR_IN m_GroupAddr;

ip_mreq m_mrMReq;

int m_nTTL;

CString m_sLocalIP;

public:
CMulticast(CWnd * pParent, CString & localIP);

virtual ~CMulticast();

virtual void OnReceive(int nErrorCode);

BOOL InitSock(void);

void DeleteThis();

int SendData(int nIndex, int len);

SPACKET SendBuff[SEND_BUFF_COUNT];
SPACKET ReveiveBuff[RECEIVE_BUFF_COUNT];
SPACKET AckBuff;
};


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

#include "stdafx.h"
#include "Multicast.h"
#include ".\multicast.h"


// CMulticast

CMulticast::CMulticast(CWnd * pParent, CString & localIP)
{
m_pParent = pParent;
m_sLocalIP = localIP; //如果不设置请使用空字符串
m_nTTL = 3; //允许经过的路由个数

// 初试化个个成员变量
memset(&m_mrMReq, 0, sizeof(m_mrMReq));
memset(&m_GroupAddr, 0, sizeof(m_GroupAddr));
memset(ReveiveBuff, 0, sizeof(SPACKET)* RECEIVE_BUFF_COUNT);
memset(SendBuff, 0, sizeof(SPACKET)* SEND_BUFF_COUNT);

// 使用函数初始化 否则容易产生内存错误

InitSock();
}

CMulticast::~CMulticast()
{

// 使用函数析构 否则容易产生内存错误
DeleteThis();
}

void CMulticast::DeleteThis()
{

// 离开多播组
setsockopt (m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq));
}

// CMulticast 成员函数

void CMulticast::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
int i=0,len=0;
UINT nPort = 0;
CString * pStr = new CString; // 由使用者使用完后释放。
for (i=0;i<RECEIVE_BUFF_COUNT;i++)
{
if (ReveiveBuff[i].used == 0)
{
break;
}
}

len = ReceiveFrom(&ReveiveBuff[i], MAX_MUC_PACKET_SIZE, *pStr, nPort);
if (len > 0)
{ //通知父窗口,消息第一个参数 i 为接收到的消息在缓冲区的索引值
::PostMessage(m_pParent->GetSafeHwnd(), WM_MUC_RECEIVE_DATA, (WPARAM)i, (LPARAM)pStr);
}

CAsyncSocket::OnReceive(nErrorCode);
}

BOOL CMulticast::InitSock(void)
{ //创建 Socket 并绑定地址为 m_sLocalIP
if(!Create(MU_PORT, SOCK_DGRAM, FD_READ,m_sLocalIP))
return FALSE;

BOOL bMultipleApps = TRUE; /* 允许复用端口*/
SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

/* 填写 m_GroupAddr 的字段值 */
memset(&m_GroupAddr, 0, sizeof(m_GroupAddr));
m_GroupAddr.sin_family = AF_INET;
m_GroupAddr.sin_addr.s_addr = inet_addr(MU_GROUP_IP);
m_GroupAddr.sin_port = htons((USHORT)MU_PORT);

/* 加入多播组 */
m_mrMReq.imr_multiaddr.s_addr = inet_addr(MU_GROUP_IP); /* 多播组地址 */
m_mrMReq.imr_interface.s_addr = inet_addr(m_sLocalIP); /* 要使用的本地地址,需要与 绑定的地址相同*/
if(setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq)) < 0)
return FALSE;

/* 设置 TTL 值,与跨越的路由设备个数相关,一般不要设置太大 1-127 */
if(SetSockOpt(IP_MULTICAST_TTL, &m_nTTL, sizeof(int), IPPROTO_IP) == 0)
return FALSE; /* 设置 TTL 发生错误 */

return TRUE;

}

int CMulticast::SendData(int nIndex, int len)
{
if (nIndex == -1)
{ // 发送确认数据
return SendTo(&AckBuff, len, MU_PORT, MU_GROUP_IP);
}
if (nIndex >= SEND_BUFF_COUNT || nIndex < 0)
{
return 0;
}
return SendTo(&SendBuff[nIndex], len, MU_PORT, MU_GROUP_IP);
}


使用这个多播类,就想使用一般的UDP套接字一样。

发送数据 默认使用 索引为0的缓冲区

SPACKET * pak = &m_pMuSock->SendBuff[0];
int len = str.GetLength();
pak->used = 1;
pak->nType = MSG_TYPE_ONEUSER;
pak->nUnused = 0;
pak->time= CTime::GetCurrentTime().GetTime();
strncpy(pak->data, str, len);
pak->data[len] = 0;

pak->nUnused = inet_addr(*pStr);
m_pMuSock->SendData(i, len + PACKET_HEAD_SIZE +1);

接收数据 在 DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 中添加

LRESULT CTestDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
SPACKET * pak;
CString * psIP;
switch(message)
{
case WM_MUC_RECEIVE_DATA:
pak = &m_pMuSock->ReveiveBuff[wParam];
psIP = (CString *)lParam;
case WM_MUC_RECEIVE_DATA:
pak = &m_pMuSock->ReveiveBuff[wParam];
psIP = (CString *)lParam;
if (pak->nType == MSG_TYPE_ALLUSER)
{
//处理消息
}
delete psIP;
pak->used = 0;
break;

}

龍月 2009-07-28
  • 打赏
  • 举报
回复
麻烦您百度一下:组播跨网段
可以搜出很多。。。
组播和广播都可以跨网段
北飞 2009-07-28
  • 打赏
  • 举报
回复
ly_longyue 大哥能再说详细点吗?谢谢
龍月 2009-07-28
  • 打赏
  • 举报
回复
使用多播实际上是使用知名地址和知名端口的通讯,所以这还可以在IP冲突严重的局域网中使用。因为一个组播组确定了唯一的一个MAC地址,所以无须ARP协议解析MAC地址。呵呵!

北飞 2009-07-28
  • 打赏
  • 举报
回复
那飞秋那种跨网段甚至可以说是穿越局域网的通信用的是您说的这种方式么?

4,356

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧