.net3.5下的Socket通信框架
.net3.5下的Socket通信框架
1:前言
写博客时间不短了但是一直不知道怎么开头。索性就开门见山吧。
这篇文章主要给大家介绍.net3.5下的Socket通信,主要从事件池,缓冲区以及协议三个方面给大家阐述。最后附上个我调试通过的项目。怎么说那?还是来个目录吧
A:通信框架图
B:通信流程图
C:简单介绍
D:源代码
先上通信框架图
首先声明这个源代码工程地址是http://www.codeproject.com/KB/IP/socketasynceventargssampl.aspx
其中用到的协议是http://www.cnblogs.com/JimmyZhang/archive/2008/09/16/1291854.html
简单说说各个类的作用
BufferManager:缓冲区
RequestHandler:协议
SocketAsyncEventArgsPool:事件池{可重复使用的套接字对象}
SocketClient:客户端
SocketListener:服务端
再上通信流程图
接下来就是本文的重点了,看看这些代码是如何工作的。
对于服务端
1:初始化一些对象,初始化的对象包括事件池和缓冲区。
2:阻塞端口开始侦听客户端的链接。如果侦听到就readEventArgs.UserToken = e.AcceptSocket,因为我们在初始化事件池的时候只是简单的创建了SocketAsyncEventArgs对象并准备开始接收数据。在得到UserToken后就可以接收数据了。这里需要注意的是侦听到后不会等待接收过程结束才开始下一次侦听而是立即开始侦听{前提是如果事件池中有空闲对象的话}
3:接收过程。网上的例子由于没有考虑到协议所以客户端发送的数据可能会被截断。这里我们加上协议这一部分
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->private void ProcessReceive(SocketAsyncEventArgs e) {
//客户端是否关闭连接
if (e.BytesTransferred > 0) {
if (e.SocketError == SocketError.Success) {
Socket s = e.UserToken as Socket;
Int32 bytesTransferred = e.BytesTransferred;
//获取数据
String received = Encoding.ASCII.GetString(e.Buffer, e.Offset, bytesTransferred);
//增加接收字节总量
Interlocked.Add(ref this.totalBytesRead, bytesTransferred);
//Console.WriteLine("Received: \"{0}\". 服务共接受{1}字节.", received, this.totalBytesRead);
//Byte[] sendBuffer = Encoding.ASCII.GetBytes(received);
// 获取实际的字符串
string[] msgArray = handler.GetActualString(received);
// 清空缓存,避免脏读
Array.Clear(e.Buffer, e.Offset, bytesTransferred);
Boolean willRaiseEvent = false;
//如果接收到完整的消息则发送回客户端否则继续接受
foreach (string m in msgArray) {
byte[] temp = Encoding.ASCII.GetBytes(m);
e.SetBuffer(temp, 0, temp.Length);
willRaiseEvent = s.SendAsync(e);
}
if (!willRaiseEvent) {
this.ProcessSend(e);
}
}
else {
this.CloseClientSocket(e);
}
}
4:接收完成的时候我们把SocketAsyncEventArgs对象放回事件池
服务端简单说两点。第一就是阻塞和就收都是异步的互不关联的,有的同学可能会这样
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> private void StartAccept() {
SocketAsyncEventArgs accept = this.readWritePool.Pop();
this.semaphoreAcceptedClients.WaitOne();
listenSocket.AcceptAsync(accept);
}
void accept_Completed(object sender, SocketAsyncEventArgs e)
{
StartAccept();
var client = e.AcceptSocket;
e.UserToken = e.AcceptSocket;
e.Completed -= accept_Completed;
e.Completed += receive_Completed;
var buffer = new byte[1024];
e.SetBuffer(buffer, 0, buffer.Length);
client.ReceiveAsync(e);
这样写也行不过没有从代码级别把阻塞和接受分开。 我说的第二点是
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> Boolean willRaiseEvent = false;
//如果接收到完整的消息则发送回客户端否则继续接受
foreach (string m in msgArray) {
byte[] temp = Encoding.ASCII.GetBytes(m);
e.SetBuffer(temp, 0, temp.Length);
willRaiseEvent = s.SendAsync(e);
}
if (!willRaiseEvent) {
this.ProcessSend(e);
也有同学这样写
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> Byte[] sendBuffer = Encoding.Unicode.GetBytes(received);
s.Send(sendBuffer, sendBuffer.Length, SocketFlags.None);
s.ReceiveAsync(e);
这样写的话就变成同步的了。效率不高{没有测试}
对于客户端
1:异步连接服务器并用autoConnectEvent.WaitOne();等待连接完成。
2:发送数据
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->public void Send(String message) {
if (this.connected) {
//将信息转化为协议
message = String.Format("[length={0}]{1}", message.Length, message);
Byte[] sendBuffer = Encoding.ASCII.GetBytes(message);
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
completeArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
completeArgs.UserToken = this.clientSocket;
completeArgs.RemoteEndPoint = this.hostEndPoint;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
clientSocket.SendAsync(completeArgs);
//等待本次发送接收时间{不必完成仅开始就好}
AutoResetEvent.WaitAll(autoSendReceiveEvents);
//return Encoding.ASCII.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred);
}
else {
throw new SocketException((Int32)SocketError.NotConnected);
}
这里我们把自己的协议加上。这里我把发送端改了一下,因为我们要在外部获取返回的数据。
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> private void OnReceive(object sender, SocketAsyncEventArgs e) {
string msg = Encoding.ASCII.GetString(e.Buffer, 0, e.BytesTransferred);
recInfo(msg);
autoSendReceiveEvents[SendOperation].Set();
这里需要说的是AutoResetEvent.WaitAll(autoSendReceiveEvents)就是我们在发送完和启动接收后就开始下次发送而不必等接受完成。
最后送上客户端调用代码{服务端的没有改变}。
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public static void Main(string[] args) {
try {
String host = "192.168.70.100";
Int32 port = 1232;
Int16 iterations = 10;
using (SocketClient sa = new SocketClient(host, port)) {
sa.Connect();
sa.recInfo += new SocketClient.GetReceive(InfoChange);
for (Int32 i = 0; i < iterations; i++) {
if (i % 2 == 0)
sa.Send("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
else
sa.Send("222");
}
sa.Disconnect();
Console.WriteLine("Press any key to terminate the client process");
Console.Read();
}
}
catch (IndexOutOfRangeException) {
Console.WriteLine("Usage: SocketAsyncClient <host> <port> [iterations]");
}
catch (FormatException) {
Console.WriteLine("Usage: SocketAsyncClient <host> <port> [iterations]." +
"\r\n\t<host> Name of the host to connect." +
"\r\n\t<port> Numeric value for the host listening TCP port." +
"\r\n\t[iterations] Number of iterations to the host.");
}
catch (Exception ex) {
Console.WriteLine("ERROR: " + ex.Message);
}
}
static void InfoChange(string info) {
Console.WriteLine("收到信息:{0}", info);
写在最后
本来想放上代码的。不过由于代码大部分来自于网上放上来有点。。。
如果哪位同学想要我调试过的就留个邮箱,我挨个给你们发。
考虑到要的同学太多就放上源代码
源代码
.net3.5下的Socket通信框架相关推荐
- 如何在Android平台下进行Socket通信
如何在Android平台下进行Socket通信 首先在Java se平台上新建一个Socket服务端: public static void main(String[] args) { try { S ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-代码解析...
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍一文之中我们对AgileEAS.NET S ...
- linux下的socket通信
linux下的socket通信 在linux下,无论多么复杂的服务器或客户端程序,无论什么编程语言实现的,其底层都离不开linux内核提供的系统调用(也就十多个函数),其网络通信的基本流程一定如下所述 ...
- Windows下的socket通信,实时发送消息
在客户端与服务端进行信息交互的时候,我们经常想让他们进行实时对话,下面我将给出客户端与服务器实时通信的代码,采用C语言与C++混合编写,基于tcp协议,键盘输入想发送的数据,接收到数据之后,对数据进行 ...
- java socket tomcat_在Tomcat环境下使用socket通信
最近在做一个APP的服务器端,但是APP和服务器端使用的是HTTP的通信协议,而另一方与服务器端通信却使用的是自定义的通信协议.具体的系统拓扑如下: 为了完成以上的需求,一般的解决方案有两种: 自己实 ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答...
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- 大并发量socket 通信框架
学 JAVA 必然要学习网络通信socket,当我们了解了socket的通信原理后,想要写出一个健壮的socket模块还是很不容易的,scoket+线程+IO,我们使用最原始的代码去实现,往往写出的代 ...
- linux下的socket通信小程序分享——第三圣子
第三圣子 最近学习unix网络编程,感觉东西零零碎碎,比较混乱.因此决定整理以下,发一个小博客.一来可以与大家分享以下,二来可以总结提高一下所学的东西.话说:竹子为什么长的高,因为它喜欢总结阿--^_ ...
- 02、处于不同局域网下的Socket通信(网络部分理论知识)
目录 一.服务器 1.服务器的种类和功能 2.服务器的操作系统 3.IIs.Apache.Tomcat 4.云服务器 弹性云服务器(Elastic Cloud Server,ECS) 云服务器安全组 ...
最新文章
- 多线程编程有什么用途_为什么建议你一定要学懂C++
- STM32驱动LCD原理
- C++ map的基本和高级操作
- Acrobat Pro DC 教程,如何将纸质文档转换为可搜索的 PDF 文件?
- cygwin的离线安装包
- ubuntu LVM
- Drools规则引擎入门小demo
- 基于Jsp+Servlet的在线考试系统
- xadsafe做暗刷_XADsafe去广告热心网友共享规则库部分开源(11月13更新)
- 彻底卸载360安全卫士的方法
- 小程序navigateTo失效
- Redis(五)深入了解Redis核心设计原理 SDS类型(String)redis如何扩容 五种结构底层数据结构 结构变换条件 如何配置条件 GEO使用 ACL
- 老板掌控公司方向的三张图
- matlab批量导入excel表格数据,matlab导入excel表格数据-如何用matlab读取多个excel表格数据,将每个表格数......
- 网站ui设计是什么意思【萧蕊冰】
- 【操作系统】--面包师问题
- python电子病历交接班系统_电子病历系统开发经验共享,大家共勉!
- 【通信原理】复习笔记
- SecureCRT 5.1.3 及注册码
- 道路运输行政许可之客运经营许可
热门文章
- 齐头并进(51Nod-1649)
- 高精除(信息学奥赛一本通-T1308)
- 47 MM配置-采购-条件-定价过程-定义方案确认
- 36 FI配置-财务会计-应收账款和应付账款-为供应商定义备选统驭科目
- php导入excel源码,利用PHPExcel类库,实现PHP导出导入Excel表格Excel文件!
- 导航栏iframe公共样式_中秋节微信公众号推文样式素材推荐
- kgdb调试内核无法执行断点及kdb-22:Permisson denied
- mysql set substring_MySQL substring()函数
- CUDA GPU内存结构
- Ubuntu18.04.1系统安装mmdetection(含torch、torchvision、mmcv-full)