当前位置: 首页 > news >正文

C#的Socket程序(TCP)

C#的Socket程序(TCP)

<!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> <rdf:Description rdf:about="http://www.cnblogs.com/dlwang2002/archive/2007/10/15/924803.html" dc:identifier="http://www.cnblogs.com/dlwang2002/archive/2007/10/15/924803.html" dc:title="C#的Socket程序(TCP)" trackback:ping="http://www.cnblogs.com/dlwang2002/services/trackbacks/924803.aspx" /> </rdf:RDF> -->

其实只要用到Socket联接,基本上就得使用Thread,是交叉使用的。
C#封装的Socket用法基本上不算很复杂,只是不知道托管之后的Socket有没有其他性能或者安全上的问题。
在C#里面能找到的最底层的操作也就是socket了,概念不做解释。
程序模型如下:
WinForm程序 : 启动端口侦听;监视Socket联接情况;定期关闭不活动的联接;
Listener:处理Socket的Accept函数,侦听新链接,建立新Thread来处理这些联接(Connection)。
Connection:处理具体的每一个联接的会话。

1:WinForm如何启动一个新的线程来启动Listener:
//start the server
private void btn_startServer_Click(object sender, EventArgs e)
{
//this.btn_startServer.Enabled = false;
Thread _createServer = new Thread(new ThreadStart(WaitForConnect));
_createServer.Start();
}
//wait all connections
private void WaitForConnect()
{
SocketListener listener = new SocketListener(Convert.ToInt32(this.txt_port.Text));
listener.StartListening();
}
因为侦听联接是一个循环等待的函数,所以不可能在WinForm的线程里面直接执行,不然Winform也就是无法继续任何操作了,所以才指定一个新的线程来执行这个函数,启动侦听循环。
这一个新的线程是比较简单的,基本上没有启动的参数,直接指定处理函数就可以了。
2:Listener如何启动循环侦听,并且启动新的带有参数的线程来处理Socket联接会话。
先看如何建立侦听:(StartListening函数)
IPEndPoint localEndPoint = new IPEndPoint(_ipAddress, _port);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(20);//20 trucks

// Start listening for connections.
while (true)
{
// here will be suspended while waiting for a new connection.
Socket connection = listener.Accept();
Logger.Log("Connect", connection.RemoteEndPoint.ToString());//log it, new connection
……
}
}……
基本步骤比较简单:
建立本机的IPEndPoint对象,表示以本机为服务器,在指定端口侦听;
然后绑定到一个侦听Socket上;
进入while循环,等待新的联接;
如果有新的联接,那么建立新的socket来对应这个联接的会话。
值得注意的就是这一句联接代码:listener.Accept()。执行这一句的时候,程序就在这个地方等待,直到有新的联检请求的时候程序才会执行下一句。这是同步执行,当然也可以异步执行。

新的联接Socket建立了(Accept之后),对于这些新的socket该怎么办呢?他们依然是一个循环等待,所以依然需要建立新的Thread给这些Socket去处理会话(接收/发送消息),而这个Thread就要接收参数了。
Thread本身是不能接收参数的,为了让它可以接收参数,可以采用定义新类,添加参数作为属性的方法来解决。
因为每一个Socket是一个Connection周期,所以我定义了这么一个类public class Connection。这个类至少有这样一个构造函数public Connection(Socket socket); 之所以这么做,就是为了把Socket参数传给这个Connection对象,然后好让Listener启动这个Thread的时候,Thread可以知道他正在处理哪一个Socket。
具体处理的方法:(在Listener的StartListening函数,ocket connection = listener.Accept();之后)
Connection gpsCn = new Connection(connection);
//each socket will be wait for data. keep the connection.
Thread thread = new Thread(new ThreadStart(gpsCn.WaitForSendData));
thread.Name = connection.RemoteEndPoint.ToString();
thread.Start();
如此一来,这个新的socket在Accept之后就在新的Thread中运行了。
3:Connection的会话处理
建立了新的Connection(也就是socket),远程就可以和这个socket进行会话了,无非就是send和receive。
现在先看看怎么写的这个线程运行的Connection. WaitForSendData函数
while (true)
{
bytes = new byte[1024];
string data = "";
//systm will be waiting the msg of receive envet. like Accept();
//here will be suspended while waiting for socket income msg.
int bytesRec = this._connection.Receive(bytes);
_lastConnectTime = DateTime.Now;
if (bytesRec == 0)//close envent
{
Logger.Log("Close Connection", _connection.RemoteEndPoint.ToString());
break;
}
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
//…….handle your data.
}
可以看到这个处理的基本步骤如下:
执行Receive函数,接收远程socket发送的信息;
把信息从字节转换到string;
处理该信息,然后进入下一个循环,继续等待socket发送新的信息。
值得注意的有几个:
1:Receive函数。这个函数和Listener的Accept函数类似。在这个地方等待执行,如果没有新的消息,这个函数就不会执行下一句,一直等待。
2:接收的是字节流,需要转化成字符串
3:判断远程关闭联接的方式
4:如果对方的消息非常大,还得循环接收这个data。
4:如何管理这些联接(thread)
通过上边的程序,基本上可以建立一个侦听,并且处理联接会话。但是如何管理这些thread呢?不然大量产生thread可是一个灾难。
管理的方法比较简单,在Listener里面我定义了一个静态的哈希表(static public Hashtable Connections=new Hashtable();),存储Connection实例和它对应的Thread实例。而connection中也加入了一个最后联接时间的定义(private DateTime _lastConnectTime;)。在新链接建立的时候(Listener的Accept()之后)就把Connection实例和Thread实例存到哈希表中;在Connection的Receive的时候修改最后联接时间。这样我们就可以知道该Connection在哪里,并且会话是否活跃。
然后在Winform程序里头可以管理这些会话了,设置设置超时。

相关文章:

  • 使用hibernate的Criteria来动态改变对象关联方式
  • c语言列指针的形式,C语言基础之指针
  • 关于spring的配置文件的分模块策略
  • c语言printf输出多一行,【提问】[已解决]初学C语言,请帮忙看下我这个源码为什么老是多输出一行PRINTF...
  • 数据压缩备份
  • c语言选择排序教程,选择排序法(C语言)
  • 已知特征值求特征向量c语言,C++ Eigen库计算矩阵特征值及特征向量
  • 数据库设计范式深入浅出
  • 数据库设计三大范式应用实例剖析
  • c语言 已知三位数数列,C语言程序设计100例之(23):数列求和
  • android 实现qq动画,Android实现仿QQ登录界面背景动画效果
  • “磁碟机”病毒详尽分析报告
  • android自动无限轮播,Android安卓比较完美的无限自动轮播
  • 端点安全:为何只有检测率远远不够
  • android 添加json动画,Lottie 站在巨人的肩膀上实现 Android 酷炫动画效果
  • 4. 路由到控制器 - Laravel从零开始教程
  • Cookie 在前端中的实践
  • JAVA_NIO系列——Channel和Buffer详解
  • js面向对象
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • SQLServer之索引简介
  • win10下安装mysql5.7
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 将 Measurements 和 Units 应用到物理学
  • 浏览器缓存机制分析
  • 新手搭建网站的主要流程
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • !!Dom4j 学习笔记
  • #Lua:Lua调用C++生成的DLL库
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (Python) SOAP Web Service (HTTP POST)
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .gitattributes 文件
  • .net 7 上传文件踩坑
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .net 发送邮件
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .net的socket示例
  • .net网站发布-允许更新此预编译站点
  • .Net中间语言BeforeFieldInit
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [AutoSar]BSW_OS 01 priority ceiling protocol(PCP)
  • [CSS]浮动
  • [C进阶] 数据在内存中的存储——浮点型篇
  • [docker]docker网络-直接路由模式
  • [HNOI2010]BUS 公交线路
  • [LeetCode] Sort List
  • [LeetCode]: 145: Binary Tree Postorder Traversal