C#中的TCP通讯与UDP通讯
最近做了一个项目,主要是给Unity3D和实时数据库做通讯接口。虽然方案一直在变:从开始的UDP通讯变为TCP通讯,然后再变化为UDP通讯;然后通讯的对象又发生改变,由与数据库的驱动进行通讯(主动推送数据给驱动,数据库中数据发生变化把数据以UDP报文形式发送客户端)改为与实时数据库进行直接通讯(自己发送报文修改数据库中的数据,自己请求需要获取的数据并接收自己请求的数据);现在这个项目基本完结,由于这个过程既接触到了UDP又接触到了TCP,现在对其进行一番总结。
阅读目录
- TCP通讯协议与UDP通讯协议的区别
- TCP通讯(用TCP协议对报文进行发送与接收)
- UDP通讯(用UDP协议对报文进行发送与接收)
- UDP协议实现一台PC机多客户端与服务端进行通讯
- UDP协议和TCP协议网络通讯的测试方法
- 总结
TCP通讯协议与UDP通讯协议的区别
TCP与UDP都是网络SOCKET通信协议,其最大的区别在于UDP是一种不可靠的网络通讯服务,而TCP是一种可靠的网络通信服务。众所周知,TCP通过三次握手来实现网络通讯的,这一机制保证了校验数据,保证了可靠性;而UDP是不用创建链路把报文发送出去即可,它会根据IP地址自寻目的地,如果这个过程出现了问题就会把数据丢掉,但是UDP的传输速率比较高,反应速度较快。两种传输方式各有利弊,要视具体的需求来选择不同的通信协议了。
TCP通讯(用TCP协议对报文进行发送与接收)
在C#中已经提供了比较成熟的TCP通讯相关的类库以及方法。因为要获取数据库中的实时数据,所以处理思路就是,在程序开始的时候开启一个线程,对服务器端的数据进行接收,把接收到的数据做相应的处理;如果需要修改数据,那么就提供一个接口,对服务器端的数据库中的数据进行修改,具体代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Web; namespace Rdbclass
{
public class Rdb
{
ArrayList arrDatalist = new ArrayList();//存储需要发送的数据
ArrayList arrSendDataList = new ArrayList();//存储改变了值的数据 private TcpClient client;//声明TCP客户端
private ThreadStart threadStart;//声明一个线程
private Thread client_th;
private string sip;
private int iPort;
//构造函数进行数据的初始化
public Rdb(string strip, ArrayList list, int Port)
{
arrDatalist = list;
sip = strip;
iPort = Port;
connect_s();
} //连接服务器
private void connect_s()
{
try
{
client = new TcpClient(sip, iPort);
threadStart = new ThreadStart(AcceptMsg);
client_th = new Thread(threadStart);
client_th.Start();
}
catch (System.Exception ex)
{
throw new Exception(ex.ToString());
}
}
//接收数据方法,在程序运行的时候开启一个线程进行数据的接收
private void AcceptMsg()
{
NetworkStream ns = client.GetStream();
//字组处理
while (true)
{
try
{
byte[] bytes = new byte[];
byte[] sendBytes = new byte[];
NetworkStream sendStream1 = client.GetStream();
int bytesread = ns.Read(bytes, , bytes.Length);
string msg = Encoding.UTF8.GetString(bytes, , bytesread);
for (int i = ; i < arrDatalist.Count; i++)
{
string strItemData = (string)arrDatalist[i];
string[] Data = strItemData.Split('|');
string[] DataReceive = msg.Split('|'); if (Data[].ToString() == DataReceive[].ToString() && DataReceive[].ToString() == "val")
{
arrDatalist.RemoveAt(i);
string strNewData = DataReceive[] + "|" + DataReceive[];
arrDatalist.Add(strNewData);
sendBytes = Encoding.UTF8.GetBytes("ret|" + DataReceive[] + "|ok!");
sendStream1.Write(sendBytes, , sendBytes.Length);
sendStream1.Flush();
}
}
ns.Flush();
} catch (System.Exception ex)
{
throw new Exception(ex.ToString());
}
}
} private void Sendmessage()
{
if (client == null)
return;
NetworkStream sendStream = client.GetStream();
Byte[] sendBytes;
if (arrSendDataList.Count > )
{
for (int i = ; i < arrSendDataList.Count; i++)
{
string message = arrSendDataList[i].ToString();
arrSendDataList.RemoveAt(i);
sendBytes = Encoding.UTF8.GetBytes(message);
sendStream.Write(sendBytes, , sendBytes.Length);
sendStream.Flush();
}
}
} //修改原始数据里面的值并发送数据
public void ModiData(string strName, string value)
{
try
{
int iCount = arrDatalist.Count;
if (iCount > )
{
for (int i = ; i < iCount; i++)
{
string strItemData = (string) arrDatalist[i];
string[] Data = strItemData.Split('|');
if (Data[].ToString() == strName)
{
arrDatalist.RemoveAt(i);
string strNewData = Data[] + "|" + value;
arrDatalist.Add(strNewData);
arrSendDataList.Add("val|" + strNewData);
break;
}
}
Sendmessage();
}
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
//退出整个应用
public void Exit()
{
if (client != null)
{
client.Close();
}
}
}
}
UDP通讯(用UDP协议对报文进行发送与接收)
UDP通讯中,服务器端不会主动的去推送数据到客户端,那么就需要客户端定时轮询服务器端的数据了。思路是先发送请求数据,然后让此线程休眠100ms接收服务器端返回过来的请求数据,其具体代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading; namespace RdbUDP
{
public class UPDRdc
{
ArrayList arrDatalist = new ArrayList();//存储点表的数据
ArrayList arrSendDataList = new ArrayList();//存储改变了的值的数据
private string strSendIP ;//需要发送数据的地址
private int ISendport ; //发送的端口号
IPEndPoint remoteSendIpep;
ArrayList arrSendlist = new ArrayList(); //
/// <summary>
/// 用于UDP发送的网络服务类
/// </summary>
private UdpClient udpcSend; public UPDRdc(ArrayList list, string SendIP, int SendPort)
{
arrDatalist = list;
strSendIP = SendIP;
ISendport = SendPort;
StartRecvData();//初始化接收数据
} //初始化发送节点
private void SetSendPoint()
{
remoteSendIpep = new IPEndPoint(
IPAddress.Parse(strSendIP), ISendport); // 发送到的IP地址和端口号
} //接收数据
/// <summary>
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StartRecvData()
{
SetSendPoint();
udpcSend = new UdpClient();
} //修改原始数据里面的值并发送数据
public void ModiData(string strName, string value)
{
int iCount = arrDatalist.Count;
if (iCount > )
{
for (int i = ; i < iCount; i++)
{
string strItemData = (string)arrDatalist[i];
string[] Data = strItemData.Split(',');
if (Data[].ToString() == strName)
{
arrDatalist.RemoveAt(i);
string strNewData = Data[] + "," + value;
arrDatalist.Add(strNewData);
arrSendDataList.Add("setvardata,0;" + strNewData+";");
break;
}
}
NeedSendMessage();
}
} //退出整个应用
public void Exit()
{
if (udpcSend != null)
{
udpcSend.Close();
} } private void NeedSendMessage()
{
if (arrSendDataList.Count > )
{
for (int i = ; i < arrSendDataList.Count; i++)
{
string message = arrSendDataList[i].ToString();
arrSendDataList.RemoveAt(i);
Thread thrSend = new Thread(SendMessage);
thrSend.Start(message);
Thread.Sleep();
}
} }
/// <summary>
/// 发送信息
/// </summary>
/// <param name="obj"></param>
private void SendMessage(object obj)
{
string message = (string)obj;
byte[] sendbytes = Encoding.Default.GetBytes(message);
GetDataSendMessage(sendbytes, sendbytes.Length, remoteSendIpep);
} //发送数据
public void GetDataSendMessage(byte[] sendbytes, int len, IPEndPoint remoteSendIpep)
{
udpcSend.Send(sendbytes, len, remoteSendIpep);
} //接收数据
public string GetDataRevMessage( IPEndPoint remoteSendIpep)
{
IPEndPoint remoteSendIpep1 = new IPEndPoint(
IPAddress.Parse(strSendIP), );
byte[] bytRecv = udpcSend.Receive(ref remoteSendIpep);
string message = Encoding.Default.GetString(
bytRecv, , bytRecv.Length);
return message;
} }
}
UDP协议实现一台PC机多客户端与服务端进行通讯
如果在同一台PC机器上去做UDP通讯,由于在客户端进行初始化的时候我们会对UDPClient进行创建,如果是同客户端创建同样的对象就会报“同一个端口仅能创建一个”的错误,解决办法是改变不同客户端的new UdpClient(UdpClient标识)中的UdpClient标识了,并且在接收数据的时候只能限制其IP,其端口号指定为任意(也就是0了),其具体代码如下:
UDP协议和TCP协议网络通讯的测试方法
我们在完成了编码之后,我们该怎么测试我们的程序中的通讯是否是我们想象的那样了,那么我们现在就用一款工具来对我们的通讯进行测试:
运用“TCP调试助手”进行测试,极大地提高我们的测试效率和排查问题原因:
总结
在C#中做UDP和TCP通讯对于开发者来说区别不大,因为.NET已经有完善并且成熟的公共类和方法供我们来进行相关的通讯工作,只要我们稍加学习就可以在C#中运用这两种通讯方式了;在测试的过程中由于是多方协作或许会遇到一些这样那样的问题,但是先通过工具在我们自己本机测试通信情况之后就很好地去定位问题所在了。
如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
如果您希望更容易地发现我的新博客,不妨点击一下绿色通道的【关注我】。
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客。
C#中的TCP通讯与UDP通讯的更多相关文章
- LWIP裸机环境下实现TCP与UDP通讯
前面移植了LWIP,并且简单的实用了DHCP的功能,今天来使用一下实际的数据通讯的功能 首先是实现TCP客户端,我先上代码 #ifndef __TCP_CLIENT_H_ #define __TCP_ ...
- JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用
JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例, ...
- java基础55 UDP通讯协议和TCP通讯协议
本文知识点(目录): 1.概述 2.UDP通讯协议 3.TCPP通讯协议 1.概述 1.在java中网络通讯作为Socket(插座)通讯,要求两台都必须安装socket. 2.不同的 ...
- onps栈使用说明(3)——tcp、udp通讯测试
4. tcp客户端 在协议栈源码工程下,存在一个用vs2015建立的TcpServerForStackTesting工程.其运行在windows平台下,模拟实际应用场景下的tcp服务器.当tcp客户端 ...
- LWIP裸机环境下实现TCP与UDP通讯(转)
源: LWIP裸机环境下实现TCP与UDP通讯
- 在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?(QQ 为什么采用 UDP 协议,而不采用 TCP 协议实现?)
为了解决这题,可以具体看看下面这个讨论. 解灵运工程师 185 人赞同 某次架构师大会上那个58同城做即时通信的人说:原因是因为当时没有epoll这种可以支持成千上万tcp并发连接的技术,所以他们使用 ...
- 计算机网络中的TCP/UDP协议到底是怎么回事(一)
TCP/IP五层网络结构模型 物理层:物理层建立在物理通信介质的基础上,作为系统和通信介质的接口,用来实现数据链路实体间透明的比特 (bit) 流传输.只有该层为真实物理通信,其它各层为虚拟通信 数据 ...
- UDP通讯协议
常见的通讯协议有udp和tcp. 先来简单了解一下这两个协议各自的特点: UDP: --将数据及源.目的封装在数据包中,不需要建立连接: --每个数据包的大小限制在64k以内: --因无连接,是不可靠 ...
- QUdpSocket-Qt使用Udp通讯实现服务端和客户端
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QUdpSocket-Qt使用Udp通讯实现服务端和客户端 本文地址:https:// ...
随机推荐
- Oracle数据库之PL/SQL游标
1. 游标概念 字面意思是游动的光标,是指向上下文区域的句柄或指针. 在PL/SQL块中执行CRUD操作时,ORACLE会在内存中为其分配上下文区.用数据库语言来描述游标就是:映射在上下文区结果集中一 ...
- OnCreate
用于创建插入符 /* CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm);//得到窗口字体信息 CreateSolidCaret ...
- 总结一下apply和call的异同点
call, apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例,也就 ...
- 解决.VS2012+EF5.0开发的网站在window server2003上无法部署的问题(转载)
转载:http://www.cnblogs.com/eggTwo/p/3653825.html (一)前 言 ...
- css画小米、遨游logo
狠简单的2个Logo,用纯css写出来,觉得挺好玩的. <!DOCTYPE html> <html> <head> <meta charset="u ...
- apache2.2 虚拟主机配置详解
一.修改httpd.conf 打开appserv的安装目录,找到httpd.conf文件,分别去掉下面两行文字前面的#号. #LoadModule vhost_alias_module modules ...
- Day02
1.os.system()和os.popen() os.popen() 功能强于os.system() , os.popen() 可以返回回显的内容,以文件描述符返回 eg: import os re ...
- HAPROXY 配置项/配置实例
HAPROXY 配置项/实例 常用配置选项: OPTION 选项: option httpclose :HAProxy会针对客户端的第一条请求的返回添加cookie并返回给客户端,客户端发送后续请求时 ...
- 無心插柳的Linux學習者代言人——蔡德明
誰是「蔡德明」恐怕沒有多少人知道,不過提到「鳥哥」這個稱號,在臺灣的Linux社群幾乎是無人不知無人不曉,蔡德明正是鳥哥的本名.鳥哥究竟多有名? 如果你是有意學習Linux的初學者,卻不知如何下手,1 ...
- 51单片机 Keil C 延时程序的简单研究
应用单片机的时候,经常会遇到需要短时间延时的情况.需要的延时时间很短,一般都是几十到几百微妙(us).有时候还需要很高的精度,比如用单片机驱动DS18B20的时候,误差容许的范围在十几us以内,不然很 ...