.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需要注意。

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

源代码下载

  

闲来无事,写个基于TCP协议的Socket通讯Demo的更多相关文章

  1. 闲来无事,写个基于UDP协议的Socket通讯Demo

    项目一期已经做完,二期需求还没定稿,所以最近比较闲. 上一篇写的是TCP协议,今天写一下UDP协议.TCP是有连接协议,所以发送和接收消息前客户端和服务端需要建立连接:UDP是无连接协议,所以发送消息 ...

  2. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  3. 基于TCP 协议的socket 简单通信

    DNS 服务器:域名解析 socket 套接字 : ​ socket 是处于应用层与传输层之间的抽象层,也是一组操作起来非常简单的接口(接受数据),此接口接受数据之后,交由操作系统 为什么存在 soc ...

  4. 基于TCP协议的socket套接字编程

    目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...

  5. Java:基于TCP协议网络socket编程(实现C/S通信)

    目录 一.前言:TCP原理简介 二.Socket编程通信 三.TCP服务器端(具体代码) 四.TCP客户端(具体代码) 五.通信效果演示 六."创意"机器人:价值一个亿的AI核心代 ...

  6. 基于TCP协议的网络通讯流程

    不多说了,先上个图: 从上面的图中可以看出来,基于TCP协议进行通讯可以大致分成以下几个阶段: 1. 首先是在服务器端, TCP Sever调用socket(), bind(), listen()完成 ...

  7. 基于TCP实现的Socket通讯详解

    Socket通信是基于TCP协议进行的传输层通信,是在应用和应用之间的通信,一般应用在即时通讯上. 建立连接 用Socket创建连接需要在客户端和服务端都使用socket套接字. Linux内存创建S ...

  8. 基于TCP协议的socket编程

    什么是socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面, ...

  9. 网络编程: 基于TCP协议的socket, 实现一对一, 一对多通信

    TCP协议  面向连接 可靠的 面向字节流形式的 tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 TCP协议编码流程: 服务器端:                 客户端 实例化对 ...

随机推荐

  1. ORA-01033 ORACLE 正在初始化或关闭

    (借鉴:该方法本人亲自操作过,解决了问题!) 解决连接ORACLE错误一例:ORA-01033: ORACLE 正在初始化或关闭 客户发现连接数据库有问题,错误有: ORA-01033: ORACLE ...

  2. 高程(4):执行环境、作用域、上下文执行过程、垃圾收集、try...catch...

    高程三 4.2.4.3 一.执行环境 1.全局执行环境是最外层的执行环境. 2.每个函数都有自己的执行环境,执行函数时,函数环境就会被推入一个当前环境栈中,执行完毕,栈将其环境弹出,把控制器返回给之前 ...

  3. 项目vue2.0仿外卖APP(三)

    项目的结构如下:                   项目资源准备 准备项目的各种图片资源等等 注意:在webpack可以不用css sprite,直接用单张图片,因为它会帮忙打包. 还有SVG图片, ...

  4. paintEvent(QPaintEvent*)是系统自动调用的

    qt中函数paintEvent(QPaintEvent*)是被系统自动调用. paintEvent(QPaintEvent *)函数是QWidget类中的虚函数,用于ui的绘制,会在多种情况下被其他函 ...

  5. markdown博文测试

    一级标题 二级标题 正文 三级标题 C代码: // code #include <stdio.h> int main() { printf("Hello, World!\n&qu ...

  6. ubuntu14.04下直接修改apache2默认目录导致wordpress样式改变的解决办法

    一开始看到网上有各种各样的解决方法: 第一种是直接将 sites-available目录下的000-default.conf中的下列代码: DocumentRoot /var/www/html 修改为 ...

  7. Jquery获取select选中的文本与值

    jquery获取select选择的文本与值获取select :获取select 选中的 text :    $("#ddlregtype").find("option:s ...

  8. js学习进阶-元素获取及样式设置

    var imgs = document.querySelectorAll("article img"); 获得article元素的直接或间接子孙的所有img元素, <arti ...

  9. 修改git的远程仓库命令

    1. 修改命令 git remte origin set-url URL 2.先删后加 git remote rm origin git remote add origin git@github.co ...

  10. mysql 分页查询

    mysql,; : mysql,; -last. //如果只给定一个参数,它表示返回最大的记录行数目: mysql; 个记录行 ,n. 动态传参的分页查询 SELECT * FROM table LI ...