.Net Socket通讯可以使用Socket类,也可以使用 TcpClient、 TcpListener 和 UdpClient类。我这里使用的是Socket类,Tcp协议。

  程序很简单,一个命令行的服务端,一个命令行的客户端。服务端启动后根据输入的端口号绑定本机端口并启动侦听,客户端启动后根据输入的客户端数量、服务IP、服务端口号连接服务端。客户端连接成功后启动新线程随机发送消息到服务端并等待接收服务端返回的消息,服务端和客户端成功创建连接后启动新线程接收客户端消息并返回客户端一个消息,如此循环下去……

  上图:

图1. 客户端运行界面

图2. 服务端运行界面

图3. 项目结构

  

  

服务端关键代码

  启动侦听:

 var endPoint = new IPEndPoint(, port);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
socket.Listen(int.MaxValue);

  启动新线程接收客户端连接:

 // 启动新线程负责接受客户端连接
var socketThread = new Thread(OnSocketAccept) {IsBackground = true};
socketThread.Start(socket);
Show("服务准备就绪");

  接收客户端连接细节:

 /// <summary>
/// 建立Socket连接
/// </summary>
/// <param name="obj"></param>
private static void OnSocketAccept(object obj)
{
try
{
var socket = obj as Socket;
while (true)
{
try
{
Socket clientSocket = socket.Accept();
...
// 尝试获取锁,超时则关闭当前连接并继续下次循环
if (!Monitor.TryEnter(ClientDictLock, LockTimeOut))
{
CloseSocket(socket, key);
continue;
}
try
{
// 当然连接已存在则先关闭再缓存新连接
if (ClientDict.ContainsKey(key))
{
CloseSocket(ClientDict[key], key);
ClientDict[key] = clientSocket;
}
else
{
ClientDict.Add(key, clientSocket);
}
}
finally
{
Monitor.Exit(ClientDictLock);
}
// 启动线程池线程执行接收和发送操作
ThreadPool.QueueUserWorkItem(OnSendOrReceive, clientSocket);
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
...
}
}
}
catch (ThreadAbortException)
{
...
}
catch (Exception exception)
{
...
}
}

  发送/接收数据:

 /// <summary>
/// 接收/发送数据
/// </summary>
/// <param name="obj"></param>
private static void OnSendOrReceive(object obj)
{
try
{
var socket = obj as Socket;
...
while (true)
{
try
{
...
// 接收数据
var receiveLength = socket.Receive(receiveBuffer);
...
// 发送数据
var sendLength = socket.Send(sendBuffer);
...
}
catch (ThreadAbortException)
{
throw;
}
catch (SocketException exception)
{
CloseSocket(socket, key);
break;
}
catch (Exception exception)
{
...
}
}
}
catch (ThreadAbortException)
{
}
catch (Exception exception)
{
...
}
}

  关闭连接:

 /// <summary>
/// 关闭连接
/// </summary>
/// <param name="socket"></param>
/// <param name="key"></param>
private static void CloseSocket(Socket socket, IPEndPoint key)
{
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(true);
socket.Close();
socket.Dispose();
...
}

客户端关键代码

  连接服务端:

// 根据客户端数量建立Socket连接
for (int i = ; i <= clientNum; i++)
{
ConnetServer(address, port, i);
} /// <summary>
/// 建立Socket连接
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="id"></param>
static void ConnetServer(IPAddress address, int port, int id)
{
try
{
var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 连接服务端
clientSocket.Connect(address, port);
...
// 启动线程池线程开始发送数据和接收数据
ThreadPool.QueueUserWorkItem(OnSendOrReceive, clientSocket);
}
catch (Exception exception)
{
...
}
}

  发送/接收数据、关闭连接代码同服务端一样。

  优先使用线程池线程,服务端接受客户端连接使用独立线程(socketThread)是考虑到可能需要手工停止该线程。

  使用 Monitor.TryEnter(ClientDictLock, LockTimeOut) 和 Monitor.Exit(ClientDictLock); 是考虑到 lock 可能形成死锁,使用lock需要注意。

  本人才疏学浅,欢迎大家批评指正!

源代码下载

  

最新文章

  1. #研发解决方案#分布式并行计算调度和管理系统Summoner
  2. 【转载】C++中的基类与派生类
  3. [terry笔记]Oracle数据泵-schema导入导出
  4. CONTEXT MENU简介
  5. 开启AngularJS 1.X的学习之路(1)
  6. 添加Metasploit-payload到已有的Android项目中
  7. TCP札记
  8. Python之旅.第三章.函数4.01/4.02
  9. String的lastIndexOf()用于获取字符串中某个子字符串最后一次出现的位置
  10. MySQL数据库优化_limit_1
  11. vue中原生file上传图片
  12. kafka安装步骤
  13. OCP 062考试题库2019年新出现的考题-17
  14. 猎豹CEO傅盛:95%的人碌碌无为,只是不懂这一点!
  15. C# 键值对数据排序
  16. Django开发Web监控工具-pyDash
  17. 【记录】有趣的python模块记录
  18. java web 程序---注册页面核心代码哈希Map
  19. 第四次c++作业
  20. xcode6 添加.pch文件

热门文章

  1. vs2015全新nuget使用全析
  2. Filter实现用户名验证
  3. MVC开发模式下的用户角色权限控制
  4. SecureCRT 常用命令
  5. Windows Server 2012 R2桌面化详细设置图解
  6. windows下nginx安装、配置与使用(转载)
  7. 相机变换与Ray-Casting
  8. iOS 版本号大小比较
  9. IBM Z上邮件服务器的配置相关内容
  10. ATM+购物车