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:接收过程。网上的例子由于没有考虑到协议所以客户端发送的数据可能会被截断。这里我们加上协议这一部分
Code
<!--<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对象放回事件池
服务端简单说两点。第一就是阻塞和就收都是异步的互不关联的,有的同学可能会这样
Code
<!--<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);
这样写也行不过没有从代码级别把阻塞和接受分开。 我说的第二点是
Code
<!--<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);
也有同学这样写
Code
<!--<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:发送数据
Code
<!--<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);
}
这里我们把自己的协议加上。这里我把发送端改了一下,因为我们要在外部获取返回的数据。
Code
<!--<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)就是我们在发送完和启动接收后就开始下次发送而不必等接受完成。
最后送上客户端调用代码{服务端的没有改变}。
Code
<!--<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);
写在最后
本来想放上代码的。不过由于代码大部分来自于网上放上来有点。。。
如果哪位同学想要我调试过的就留个邮箱,我挨个给你们发。
考虑到要的同学太多就放上源代码
源代码
相关推荐
所以决定学习一下,将自己学习的内容总结分享出来,下面这篇文章主要给大家介绍了关于C# .NET中Socket简单实用框架使用的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
.NET下的socket通信源代码,源代码包括服务端和客户端的2个工程包文件,有了这个源代码那么我们学习通信就十分方便快捷了,代码采用C#编写。全部测试通过绝对没有什么问题!
C# 版socket 收发TCP协议有模版样例
一个基于VB.net的异步Socket网络TCP通信
Socket消息通信框架.docSocket消息通信框架.docSocket消息通信框架.docSocket消息通信框架.docSocket消息通信框架.doc
现在不必了,因为 使用我的 吹着北风 而构思出来 的SOCKET框架 一切问题映刃而接 里面有2个例子 第一个例子看完 入门了 第二个例子看完 登堂入室了 2个例子代码量 小与100行(排除除了WINFROM 生存的代码) 赶快...
Winform窗体程序。第一个版本没有加心跳包 第二个版本可以相互检测到断网情况 适合学习,或借鉴后二次开发
第七周-第13章节-Python3.5-Socket通信案例消息发送与接收2.avi
第七周-第12章节-Python3.5-Socket通信案例消息发送与接收1.avi
在VB.NET下利用Socket实现简单的字符串发送接收程序
用.net做的通信实例,Server可以直接接收client端发送过来信息,一个小实例程序。
基于c++的socket通信框架,windows版本,HP-SOCKET ..
C#.net同步异步SOCKET通讯和多线程总结~
java.net包socket通信,基础客户端 和 服务端的通信传输实现
vb.net(2008) socket通信例子,是研究vs.net socket的好资料
可实现多客户端通信,已测试(最好是运行服务器的电脑共享一个wifi ,客户端电脑连接这个网络,这样就可以通信了,个人的经验)
博客:https://blog.csdn.net/u014261855/article/details/109583060 unity c#实现简单前后端socket通信框架 .net dll工程,封装三个工具: 1.服务器 2.客户端 3.通用byte流客户端
.net socket通信案例-简单版 用于初学者
C#.net同步异步SOCKET通讯和多线程总结2[参照].pdf
一些人也许知道,socket这个概念最早是UNIX里面的。 用于实现TCP/IP协议族里面的通讯。 后来被各家公司抄了过去,比如微软 Sun之类的。 目前很多语言里面 ,都是使用socket实现TCP/IP通讯的。或者说大都有socket...