本文主要讲述:

1、正常通信中握手建立

2、一对多的通信

3、发送接收数据格式转换

4、资源释放

5、开启并保持服务监听

1、握手建立正常的通信通道

  项目需要通信的双方(假设是一个上位机、一个下位机)之间需要建立一个稳定的通道,以便进行通信。本项目中具体操作是:上位机作为服务器,下位机作为客户端,同时制定通信协议。上位机首先打开监听等待建立通道,下位机主动连接上位机后发送连接成功的信息到上位机,上位机根据通信协议发送数据到下位机,此时通道已经建立。但为了保险起见(同时遵循三次握手),客户端再次发送数据到上位机告知通道建立完毕。

2、一对多通信

  项目需求是一个上位机多个下位机,这就确定了上位机做为服务器端,下位机作为客户端主动连接服务器。一对一通信时只有一个socket通道,因此无论是上位机还是下位机在发送和接收数据的时候都不会存在数据乱发乱收的情况。一对多意味着上位机和下位机会建立起多个通道,因此在发送数据时需要记录哪一个下位机处于哪个socket通道中,以便进行逻辑处理。本文处理一对多通信的过程是:

1)首先建立一个对话类Session:

public class Session{public Socket ClientSocket { get; set; }//客户端的socketpublic string IP;//客户端的ippublic Session(Socket clientSocket){this.ClientSocket = clientSocket;this.IP = GetIPString();}public string GetIPString(){string result = ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString();return result;}}

2)在服务端socket监听时:

IPEndPoint loaclEndPoint = new IPEndPoint(IPAddress.Any, Port);SocketLister = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);SocketLister.Bind(loaclEndPoint);try{SocketLister.Listen(MaxConnection);while (IsRunning){ClientSocket = SocketLister.Accept();//保存socketSession newSession = new Session(ClientSocket);lock (sessionLock){sessionTable.Add(newSession.IP, newSession);}SocketConnection socketConnection = new SocketConnection(ClientSocket);socketConnection.ReceiveDatagram();//接收数据}}catch (SocketException ex){}

//声明

public Hashtable sessionTable = new Hashtable ();//包括客户端会话

private object sessionLock = new object();

 

为了便于理解,把整个服务端socket的建立都写在上面。

3)发送数据到不同的客户端

Hashtable ht = serverSocket.sessionTable;foreach (Session session in ht.Values){if (session.IP == "127.0.0.1")//example{SocketConnection socketConnection = new SocketConnection(session.ClientSocket);string str = "C300010002D2";byte[] sendBytes = StrToHexByte(str);socketConnection.Send(sendBytes);}               }

SocketConnection类已经被使用多次,写在下面:

 View Code

3、处理需要发送和接收到的数据

  项目需要是上位机获取数据进行逻辑处理,然后通过tcp/ip协议发送给下位机,下位机在接收到数据的同时发送确认信息到上位机。项目过程中,上位机在开发过程中需要调试其发送数据、接收数据是否成功,此处借助于USR-  TCP232小工具。但是涉及到一个问题,下位机发送和接收都是byte字节数组,那么开发的上位机应该如何发送和接收数据?在.net平台下C#socket通信(上),有服务器端的发送和接收函数,发送数据时将要发送的字符串转换为byte数组,接收时再将字节数组转换为16进制字符串。如下:

//字节数组转换为16进制字符串public string ByteToHexStr(byte[] bytes){string str = "";if (bytes != null){for (int i = 0; i < bytes.Length; i++){str += bytes[i].ToString("X2");}}return str;}//字符串转换为16进制byte数组public byte[] StrToHexByte(string data){data = data.Replace(" ", "");if ((data.Length % 2) != 0){data += " ";}byte[] bytes = new byte[data.Length / 2];for (int i = 0; i < bytes.Length; i++){ bytes[i] = Convert .ToByte (data.Substring (i * 2,2),16);}return bytes;}

4、资源释放

  开发项目使用平台是.net,工具vs2010,语言是C#,因为.net有垃圾回收机制,因此在实际开发中产生的托管资源都是系统自动释放完成。在做本项目时采用winform进行开发的,在此过程中发现一个问题:在关闭Form窗体是运行的系统并没有完全关闭。查找原因,应该是有资源没有被释放。而socket套接字产生的资源恰好是非托管资源,此现象表明系统中有socket资源没有被完全释放掉。因此写了一个资源释放函数:

public void Dispose(){try{this.ClientSocket.Shutdown(SocketShutdown.Both);this.ClientSocket.Dispose();this.ClientSocket.Close();this.ClientSocket = null;}catch{}}

上述函数的功能就是释放socket所产生的资源,调用后发现还是存在此问题,几经调试发现虽然把产生socket通道的监听客户端资源释放完毕,服务器端的serversocket并没有被释放,于是有了下一个函数:

public void CloseSocket(){if (serverSocket != null){serverSocket.SocketLister.Dispose();serverSocket.SocketLister = null;serverSocket.Dispose();//调用的上一个函数serverSocket = null;}}

在上述函数完成后,套接字socket所产生的资源确实被释放完毕,系统在form关闭后能真正关闭。到此资源好像已经被释放掉,但紧接着新的问题产生了:

在什么时候什么地方调用释放资源的函数?

个人简单看法:

1)系统中止时调用

2)socket通道中断时调用

补充:

5、开启并保持服务监听

在socket通信中,服务端的socket监听其实是需要一直打开并且保持的,只有这样才能随时监听连接的客户端。项目中示例:

private void button1_Click(object sender, RoutedEventArgs e){Thread thread = new Thread(new ThreadStart(StartServer));thread.Start();}public void StartServer(){int port = Convert.ToInt32(GetText(this.tbPort));string ipStr = GetText (this.tbServerIPStr);if (serverSocket == null){serverSocket = new ServerSocket(port);serverSocket.Start(ipStr);//}else{MessageBox.Show("监听已开启");}         }public void Start(string ipStr){IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Port);//IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(ipStr), Port);SocketLister = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);SocketLister.Bind(localEndPoint);try{SocketLister.Listen(MaxConnection);while (IsRunning){ClientSocket = SocketLister.Accept();//保存socketSession newSession = new Session(ClientSocket);lock (sessionLock){sessionTable.Add(newSession.IP, newSession);}SocketConnection socketConnection = new SocketConnection(ClientSocket);socketConnection.ReceiveDatagram();}}catch (SocketException ex){}}

解释:点击按钮开启新的线程thread,执行方法StartServer,StartServer调用方法Start,Start方法中使用死循环开启并保持监听。

转载于:https://www.cnblogs.com/asdyzh/p/9834050.html

.net平台下C#socket通信(中)相关推荐

  1. .net平台下C#socket通信(上)

    .net平台下C#socket通信(上) 完全是基础,新手可以随意看看,大牛可以关闭浏览页了,哈哈. 在开始介绍socket前先补充补充基础知识,在此基础上理解网络通信才会顺理成章,当然有基础的可以跳 ...

  2. java tcp read_【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...

    书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 书上的服务器 ...

  3. 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)...

    书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子--反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 1 2 3 ...

  4. java socket 二次发送_发过2次帖子,都没有了,再发。JAVA中SOCKET通信中的数据压缩问题...

    通信中要发大批量数据,发送前想进行压缩,发送完一段数据后要进行验证,然后才能继续发.我使用GZipInputStream和GZipOutputStream进行处理,但发送完一段数据后,调用zipout ...

  5. Socket 通信中read方法阻塞接收的问题

    客户端: public class Client {public static void main(String[] args) throws IOException {// 与服务器建立连接Sock ...

  6. 关于Socket通信中SOCK_STREAM和SOCK_DGRAM区别

    SOCK_STREAM   是有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送. SOCK_DGRAM   是无保障的面向消息的socket , 主要用于在网络上 ...

  7. SOCKET通信中TCP数据包大小的确定

    MSS(maximun segment size)         最大分段大小,TCP有一个最大分段大小,用于通告对端每个分段中能发送的最大TCP数据量.MSS的目的是告诉对端其重组缓冲区大小的实际 ...

  8. WINCE平台下C#应用程序中使用看门狗

    看门狗定时器(WDT,Watch Dog Timer)是单片机的一个组成部分,它实际上是一个计数器,一般给看门狗一个大数,程序开始运行后看门狗开始倒计数.如果程序运行正常,过一段时间CPU应发出指令让 ...

  9. window平台下 Eclipse Ndk开发中的Method 'NewStringUTF' could not be resolved问题

     最近需要用到android的ndk,但是在eclipse中,一直提示Method 'NewStringUTF' could not be resolved(方法"NewStringUT ...

最新文章

  1. NME的GLSL支持情况
  2. 页面生成周期中的两个Application池的详情小弟了解
  3. Google Map API V3开发(5)
  4. Java集合—List如何一边遍历,一边删除?
  5. vba将数值转化文本格式_Excel文本格式和数字格式的相互转换
  6. Android Studio开发基础之细节问题笔记
  7. 如何使用Wondershare Recoverit for Mac从崩溃的 Mac 恢复数据?
  8. OSPF——路由聚合【(汇总)含配置命令】||地址汇总计算方法——详解
  9. 在装有windows跟ubuntu的机器上重新安装windows后修复ubuntu的grub
  10. PHP实现伪静态化页面的具体实现方式
  11. python 折线图中文乱码_python matplotlib linux中文乱码问题
  12. 亚美柏科笔试题——java
  13. 安卓平板硬件测试软件,《安兔兔硬件检测》:必备的系统工具
  14. 开关电源中开关管与二极管EMI抑制方法分析
  15. 理解COM的线程套件(转)
  16. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  17. 引用 神奇的象数疗法
  18. Matlab - 产生高斯噪声
  19. 烧录flash_烧录固件完成后,配置JFLASH让程序自动运行
  20. vscode php 无法跳转到定义

热门文章

  1. nodejs 实践:express 最佳实践(五) connect解析
  2. http协议的状态码
  3. 面试感悟-------一名3年工作经验的程序员应该具备的技能
  4. 如何不屏蔽Android系统的返回按键
  5. oracle存储过程 调用java_Oracle存储过程调用Java方法
  6. leetcode算法题--左旋转字符串
  7. leetcode算法题--链表组件
  8. 破windows xp登陆密码
  9. oracle 连接查询--内连接与外连接
  10. 介绍几种SSIS部署方式