应用场景:当每一台终端开启程序后发出消息,其他终端必须收到消息然后处理

思路1:使用UDP广播。     缺点:UDP广播信号不稳定,无法确定每一台机器能接收到信号

思路2:将一台主机作为服务器,使用TCP协议用此服务器转发消息       缺点:需要另外开发服务端,且其他端必须配置IP,灵活性差。

本文讲述的是第三个思路

思路3:开启程序后先设法发现其他终端,每个终端开启一个TCP服务socket,需要发广播的机器开启多个TCP客户端连接其他终端的TCP服务端稳定通信,至于如何使所有终端能相互发现 本文使用的是用UDP广播信号暴露自己,另外还可使用局域网遍历端口等方式。

代码:

发广播暴露自己:

        Thread BroadcastTh;
/// <summary>
/// 发起广播使其他终端能检测到
/// </summary>
public void StartBroadCast()
{
try
{
if (BroadcastTh != null)
{
BroadcastTh.Abort();
}
BroadcastTh = new Thread(() =>
{
int i = ;
while (i < )
{
i++;
Thread.Sleep();
SendBroadcast("ConnectMe", );
}
});
BroadcastTh.IsBackground = true;
BroadcastTh.Start();
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
} }

这边是每隔500毫秒连续发200次,也可以无限发送广播,本人有强迫症不喜欢 while(true),况且如果开启的机器太多机器发送的广播量太多,相互监听的就越多,影响通信流量。

        public void SendBroadcast(string msg, int port)
{
try
{
Socket recieveSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, port);
byte[] data = Encoding.UTF8.GetBytes(msg);
recieveSock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Broadcast, );
recieveSock.SendTo(data, iep);
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
} }

接收广播信号,将其他终端地址添加到本地列表

  Socket BroadcastRecievesocket;

        /// <summary>
/// 监听广播信号
/// </summary>
public void ReceiveBroadcast()
{ Thread receiveThread = new Thread(() =>
{
try
{ BroadcastRecievesocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Any, );
EndPoint ep = (EndPoint)iep; BroadcastRecievesocket.Bind(iep); while (true)
{
try
{
byte[] buffer = new byte[];
BroadcastRecievesocket.ReceiveFrom(buffer, ref ep);
string msg = Encoding.UTF8.GetString(buffer);
string endaddress = ep.ToString().Split(':')[];
if (msg.Replace("\0","") == "ConnectMe")
{
if (!SocketList.ContainsKey(endaddress) && endaddress != localhost)
{
StartBroadCast();
SocketList.Add(endaddress, null);
}
}
else if (msg.Replace("\0", "") == "Offline")
{
if (SocketList.ContainsKey(endaddress))
SocketList.Remove(endaddress);
} // MessageBox.Show(time);
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
}
}
}
catch (Exception)
{
BroadcastRecievesocket.Dispose();
ReceiveBroadcast();
}
})
{
IsBackground = true
};
receiveThread.Start();
}

开启tcp服务端

        #region  TCP服务端

        Socket socketWatch;

        /// <summary>
/// 启动TCP服务端socket
/// </summary>
private void StartTCPServer()
{
try
{
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//点击开始监听时 在服务端创建一个负责监听IP和端口号的Socket
IPAddress ip = IPAddress.Any; //创建对象端口
IPEndPoint point = new IPEndPoint(ip, );
socketWatch.Bind(point);//绑定端口号
socketWatch.Listen();//设置监听
Thread thread = new Thread(Listen);
thread.IsBackground = true;
thread.Start(socketWatch);
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
}
} private void Listen(object o)
{
try
{
Socket socketWatch = o as Socket;
while (true)
{
Socket socketSend = socketWatch.Accept();//等待接收客户端连接
Thread r_thread = new Thread(Received);
r_thread.IsBackground = true;
r_thread.Start(socketSend);
}
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
}
} /// <summary>
/// 服务器端不停的接收客户端发来的消息
/// </summary>
/// <param name="o"></param>
void Received(object o)
{
try
{
Socket socketSend = o as Socket;
while (true)
{
//客户端连接服务器成功后,服务器接收客户端发送的消息
byte[] buffer = new byte[];
//实际接收到的有效字节数
int len = socketSend.Receive(buffer);
if (len == )
{
break;
}
string str = Encoding.UTF8.GetString(buffer, , len);
HandleTime(str);
}
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
}
}
#endregion

发消息时开启多个TCP客户端连接列表中IP地址对应的服务端

   Thread broadcast = new Thread(() =>
{
string[] keyStr = SocketList.Keys.ToArray();
for (int i = keyStr.Length - ; i >= ; i--)
{
try
{
Socket socketitem;
if (SocketList[keyStr[i]] != null)
{
socketitem = SocketList[keyStr[i]];
}
else
{
socketitem = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ;
IPAddress ip = IPAddress.Parse(keyStr[i]);
IPEndPoint point = new IPEndPoint(ip, );
socketitem.Connect(point);
}
DateTime dateTime = DateTime.Now;
string minisec = (Convert.ToDecimal(dateTime.Millisecond) / ).ToString("0.0000");
socketitem.Send(Encoding.UTF8.GetBytes(dateTime.ToLongTimeString() + minisec.Substring(, minisec.Length - )));
}
catch (Exception ex)
{
SimpleLog.WriteLog(ex.ToString());
SocketList.Remove(keyStr[i]);
}
}
});
broadcast.IsBackground = true;
broadcast.Start();

以上代码是部分代码。仅供参考

总结:然并卵

.net 使用TCP模拟UDP广播通信加强广播通信的稳定性的更多相关文章

  1. FTP和TCP、UDP

    应用:TFTP客户端 1. TFTP协议介绍 TFTP(Trivial File Transfer Protocol,简单文件传输协议) 是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文 ...

  2. 基于TCP与UDP协议的socket通信

    基于TCP与UDP协议的socket通信 C/S架构与初识socket 在开始socket介绍之前,得先知道一个Client端/服务端架构,也就是 C/S 架构,互联网中处处充满了 C/S 架构(Cl ...

  3. 以QQ举例 说明计算机网络中的一些概念区别(TCP与UDP,广播与单播)

    QQ 中的 广播与单播 今天简单地学习了一下 广播和多播(组播) 的知识.关于 单播和多播 的概念,可以用 QQ 中的一些例子来解释. 单播,就像 两个人聊QQ 一样,信息的接收和传递只在两个节点之间 ...

  4. 计算机网络通信、线程、tcp、udp通信及信号量等读书笔记

    一.计算机网络 1.什么是计算机网络:把分布在不同地理位置的计算机与专门的网络设备用通信线路互相连成一个规模大.功能强的系统,从而使众多计算机可以方便地互相传递信息.共享软件.硬件.数据信息等.简单来 ...

  5. TCP、UDP、Socket 通信(原)

    说明:本随笔主要演示自己给自己发送消息例子,分别使用了TCP协议.UDP协议以及socket套接字通信.使用socket套接字了模拟TCP.UDP通信实现原理.其中有些源码都来自<C#高级编程 ...

  6. 实现TCP、UDP相互通信及应用

    实验名称  Socket编程综合实验(1) 一.实验目的: 1.理解进程通信的原理及通信过程 2.掌握基于TCP和UDP的工作原理 3.掌握基本的Socket网络编程原理及方法 二.实验内容 1.掌握 ...

  7. 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP

    [源码下载] 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP 作者:webabcd 介绍重新想象 Windows 8 Store ...

  8. 高性能 TCP &amp; UDP 通信框架 HP-Socket v3.2.3 正式宣布

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包括服务端组件.client组件和 Agent 组件.广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#. ...

  9. 高性能 TCP &amp; UDP 通信框架 HP-Socket v3.2.2 正式公布

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包括服务端组件.client组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#. ...

随机推荐

  1. Pyspider的基本使用

    Pyspider的基本使用 pyspider的任务流程: 每个pyspider的项目对应一个Python的脚本,该脚本中定义了一个Handler类,它有一个on_start方法.爬取首先调用on_st ...

  2. C语言 文件操作(六)

    一.fseek() int fseek(FILE * stream, long offset, int whence); 1.参数stream 为已打开的文件指针. 2.参数offset 是偏移量,该 ...

  3. 汇编刷题:内存 MEM 单元开始存放着 10 个带符号字节数据, 编写完整程序求其中正数、 零和负数的个 数, 并分别将它们存于 PLUS、 ZERO 和 NEGO 3 个单元

    DATA SEGMENT MEM DB 12H,91H,73H,64H,20H,0A5H,0D1H,91H,0A2H,00H PLUS DB 00H ZERO DB 00H NEGO DB 00H D ...

  4. SQL表的简单操作

    创建数据库表,进行增删改查是我们操作数据库的最基础的操作,很简单,熟悉的请关闭,免得让费时间. 1.创建表: sql中创建数值类型字段要根据该字段值的增长情况选择类型: tinyint 占1个字节,长 ...

  5. 中阶d01-- web前端 html css js bootstrap

    html 页面骨架结构css 页面优化js(脚本语言) 页面和用户互动 bootstrap 前端框架,主要实现不同设备直接打开页面时播放比例设置(全屏暂时,不要滚动条)

  6. Apache Hudi 设计与架构最强解读

    感谢 Apache Hudi contributor:王祥虎 翻译&供稿. 欢迎关注微信公众号:ApacheHudi 本文将介绍Apache Hudi的基本概念.设计以及总体基础架构. 1.简 ...

  7. springboot https证书配置

    如果公司有提供证书如: 拿到证书秘钥可直接在springboot 的配置文件中配置: server.ssl.key-store=classpath:cert.pfx server.ssl.key-st ...

  8. java 方法 在jvm中的调用

    java 某个类的几个对象,这些对象调用类中一个函数,是各自拥有自己的函数代码还是使用同一段代码?30 1.java 某个类的几个对象,这些对象调用类中一个函数(普通的函数),是各自拥有自己的函数代码 ...

  9. G - Pairs Forming LCM LightOJ - 1236 (质因子分解)

    题解:这道题要从n的角度来考虑i和j. n可以表示为n=a1^p1*a2^p2*a3^p3.......n=lcm(i,j),那么质因子a1^p1,a1可以在i或者j中,并且p1=max(a1i,a1 ...

  10. Epicor RoHS Overview

    Epicor ERP具有一个旨在帮助符合指令2002/95/EC (RoHS1) and 2011/65/EU (RoHS2)的模块,特别适用于医疗设备公司. 不合格的依据是–最大浓度值和合格声明/ ...