c#tcp多线程服务器实例代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Net.NetworkInformation;
namespace 黄炎培_服务器
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 服务器倾听客户端连接线程
/// </summary>
Thread threadWatchs = null;
/// <summary>
/// 服务器套接字
/// </summary>
Socket socketServer = null;
/// <summary>
/// 服务器监控客户端连接情况的线程
/// </summary>
Thread MonitoThread = null;
/// <summary>
/// 客户端ip与套接字的集合
/// </summary>
Dictionary<string, Socket> dictSocket = new Dictionary<string, Socket>();
/// <summary>
/// 客户端ip与线程的集合
/// </summary>
Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();
/// <summary>
/// 客户端连接线程的数量
/// </summary>
long numThreadVal = 0;
/// <summary>
/// 服务器ip
/// </summary>
string strServerIP = "192.168.4.3";
/// <summary>
/// 服务器端口
/// </summary>
int serverPort = 8080;
/// <summary>
/// 缓存数据长度
/// </summary>
int receiveDataValLengt = 1024;//缓存区长度
/// <summary>
/// 用于Ping客户端
/// </summary>
Ping monitoPing = new Ping();
/// <summary>
/// 异常断开的客户端
/// </summary>
Dictionary<string, string> dictBodClient = new Dictionary<string, string>();
/// <summary>
/// 指示释放释放线程
/// </summary>
bool isClearThread = false;
ulong numDataFlow;
private void Form1_Load(object sender, EventArgs e)
{
//开启服务器
openServer(strServerIP, serverPort);
//开启服务器监控线程
MonitoThread = new Thread(monitoThreadsDynamic);
//后台线程
MonitoThread.IsBackground = true;
//启动线程
MonitoThread.Start();
}
/// <summary>
/// 开始实时监控客户端的连接情况
/// </summary>
void monitoThreadsDynamic()
{
delegateShowMseeage("开始实时监控客户端连接情况");
while (true)
{
Thread.Sleep(3000);
try
{
foreach (var vv in dictSocket)
{
PingReply reply = monitoPing.Send(vv.Key.Split(':')[0],1000);
//如果Ping通
if (reply.Status == IPStatus.Success)
{
//表示客户端连接正常
delegateShowMseeage("客户端" + vv.Key + "连接正常");
}
else
{
delegateShowMseeage("客户端" + vv.Key + "连接异常");
//添加异常客户端连接到集合dictBodClient
dictBodClient.Add(vv.Key, "old");
}
}
//释放异常连接的线程
foreach (var vvv in dictThread)
{
isClearThread = false;
foreach (var vvvv in dictBodClient)
{
if (vvv.Key == vvvv.Key)
{
isClearThread = true;
break;
}
}
if (isClearThread)
{
vvv.Value.Abort();
delegateShowMseeage("客户端" + vvv.Key + "占用的线程已释放");
}
}
//从集合合中移除异常连接的客户端
foreach (var vvv in dictBodClient)
{
//从集合中移除客户端套接字
dictSocket.Remove(vvv.Key);
//从集合中移除客户端线程
dictThread.Remove(vvv.Key);
//从列表中移除客户端套接字的远程终结点
deleteClientSocket(vvv.Key);
//跨线程显示提示数据
delegateShowMseeage("客户端" + vvv.Key + "断开连接");
}
}
catch (Exception se)
{
//MessageBox.Show(se.Message);
delegateShowMseeage(se.Message);
}
dictBodClient.Clear();
//获得当前程序运行的线程总数量
numThreadVal = Process.GetCurrentProcess().Threads.Count;
delegateShowMseeage("当前的线程总数量为:" + numThreadVal);
//获得客户端连接所占用的线程数量
numThreadVal = dictThread.LongCount();
//跨线程显示消息
delegateShowMseeage("其中客户端连接的线程数量为:" + numThreadVal);
}
}
/// <summary>
/// 开启服务器
/// </summary>
/// <param name="serverIP"></param>
/// <param name="serverPort"></param>
void openServer(string serverIP, int serverPort)
{
//实例化服务器套接字
socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//配置网络端点
IPEndPoint ipAndPort = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
try
{
//设置服务器套接字的连接参数
socketServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//将网络端点绑定到服务器套接字
socketServer.Bind(ipAndPort);
}
catch (SocketException se)
{
MessageBox.Show("异常:" + se.Message);
return;
}
//服务器开始倾听,指定最多客户端数量为10000
socketServer.Listen(10000);
//实例化服务器倾听客户端连接的线程
threadWatchs = new Thread(WatchClientConnecting);
//后台运行线程
threadWatchs.IsBackground = true;
//启动线程
threadWatchs.Start();
//显示提示消息
showMesssge("服务器启动成功");
}
/// <summary>
/// 开始倾听客户端
/// </summary>
void WatchClientConnecting()
{
//跨线程显示提示消息
delegateShowMseeage("服务器开始倾听客户端连接");
while (true)
{
//倾听新的客户端连接请求
Socket newClientConnecting = socketServer.Accept();
//添加客户端套接字的远程终结点到列表
addClientSocket(newClientConnecting.RemoteEndPoint.ToString());
//新建一条新的客户端线程
Thread newClinetThread = new Thread(receiveData);
//后台运行客户端
newClinetThread.IsBackground = true;
//启动线程,并将 新客户端的套接字 绑定到线程执行的方法
newClinetThread.Start(newClientConnecting);
//添加客户端套接字到集合
dictSocket.Add(newClientConnecting.RemoteEndPoint.ToString(), newClientConnecting);
//添加客户端接受数据的线程到集合
dictThread.Add(newClientConnecting.RemoteEndPoint.ToString(), newClinetThread);
//跨线程显示提示信息
delegateShowMseeage("新客户端:" + newClientConnecting.RemoteEndPoint.ToString());
}
}
/// <summary>
/// 接受数据
/// </summary>
/// <param name="socketConnecting"></param>
void receiveData(object socketConnecting)
{
//获取该线程绑定的客户端套接字
Socket socketClient = socketConnecting as Socket;
while (true)
{
//新建一个缓存区
byte[] receiveDataVal = new byte[receiveDataValLengt];
//数据长度
int receiveDataLength = -1;
try
{
//接受数据填入缓存区并获得数据长度
receiveDataLength = socketClient.Receive(receiveDataVal);
//接受到数据
if (receiveDataLength > 0)
{
//跨线程显示接受到的数据
delegateShowReceiveData(socketClient, receiveDataVal, receiveDataLength);
//综合处理接受到的数据
receiveDataIntegratedProcessing(receiveDataVal, receiveDataLength);
numDataFlow += (uint)receiveDataLength;
showDataFlow();
}
else
{
//从集合中移除客户端套接字
dictSocket.Remove(socketClient.RemoteEndPoint.ToString());
//从集合中移除客户端线程
dictThread.Remove(socketClient.RemoteEndPoint.ToString());
//从列表中移除客户端套接字的远程终结点
deleteClientSocket(socketClient.RemoteEndPoint.ToString());
//跨线程显示提示数据
delegateShowMseeage("客户端" + socketClient.RemoteEndPoint.ToString() + "断开连接");
//释放该线程
return;
}
}
catch
{
//从集合中移除客户端套接字
dictSocket.Remove(socketClient.RemoteEndPoint.ToString());
//从集合中移除客户端线程
dictThread.Remove(socketClient.RemoteEndPoint.ToString());
//从列表中移除客户端套接字的远程终结点
deleteClientSocket(socketClient.RemoteEndPoint.ToString());
//跨线程显示提示数据
delegateShowMseeage("异常:" + "客户端" + socketClient.RemoteEndPoint.ToString() + "断开连接");
//释放该线程
return;
}
}
}
/// <summary>
/// 综合处理接受到的数据
/// </summary>
/// <param name="datas"></param>
/// <param name="length"></param>
void receiveDataIntegratedProcessing(byte[] datas, int length)
{
//if (length == 5)
//{
// if (datas[0] == 0x11 && datas[4] == 0x11)
// {
// foreach (var clients in dictSocket)
// {
// newOneThreadSendDataToClient(clients.Value, datas, length);
// }
// }
// else if (datas[0] == 0x12 && datas[4] == 0x12)
// {
// foreach (var clients in dictSocket)
// {
// newOneThreadSendDataToClient(clients.Value, datas, length);
// }
// }
//}
//*******************************************************************
//将接受的数据发送给所有客户端
//*******************************************************************
//遍历客户端套接字的集合
foreach (var clients in dictSocket)
{
//新建一条线程发送数据到客户端
newOneThreadSendDataToClient(clients.Value, datas, length);
}
}
void newOneThreadSendDataToClient(Socket clientSocket, byte[] datas, int length)
{
//跨线程显示提示消息
delegateShowMseeage("新建一条线程准备开始发送数据");
//新建发送数据的参数模型
dataSendArgsMode sendDataArgs = new dataSendArgsMode();
//将客户端套接字绑定到模型
sendDataArgs.sockets = clientSocket;
//将数据绑定到模型
sendDataArgs.datas = datas;
//将数据长度绑定到模型
sendDataArgs.length = length;
//新建发送数据到客户端的线程
Thread threadSendDataToClient = new Thread(sendDataToClient);
//后台运行线程
threadSendDataToClient.IsBackground = true;
//启动线程,并将 发送数据的参数模型 绑定到线程执行的方法
threadSendDataToClient.Start(sendDataArgs);
}
/// <summary>
/// 发送数据到客户端
/// </summary>
/// <param name="obj"></param>
void sendDataToClient(object obj)
{
//获取用于发送数据的参数模型
dataSendArgsMode args = obj as dataSendArgsMode;
try
{
//从数据参数模型中提取数据发送到模型中的客户端
args.sockets.Send(args.datas, 0, args.length, SocketFlags.None);
//跨线程显示提示消息
delegateShowMseeage("数据:" + getStringFormByte(args.datas, args.length) + "发送到了客户端:" + args.sockets.RemoteEndPoint.ToString());
delegateShowMseeage("数据发送完毕,关闭线程");
//释放该线程
numDataFlow += (uint)args.length;
showDataFlow();
return;
}
catch
{
//从集合中移除客户端套接字
dictSocket.Remove(args.sockets.RemoteEndPoint.ToString());
//从集合中移除客户端线程
dictThread.Remove(args.sockets.RemoteEndPoint.ToString());
//从列表中移除客户端套接字的远程终结点
deleteClientSocket(args.sockets.RemoteEndPoint.ToString());
//跨线程显示提示消息
delegateShowMseeage("异常:" + "客户端" + args.sockets.RemoteEndPoint.ToString() + "断开连接" + ",关闭该线程");
//释放该线程
return;
}
}
/// <summary>
/// 从列表中删除客户端
/// </summary>
/// <param name="socket"></param>
void deleteClientSocket(string strClientSocket)
{
//封装一个方法进行委托
Action<string> actionDelegate = (x) =>
{
//从列表中移除指定客户端套接字的远程终结点
lbOnlineClient.Items.Remove(x.ToString());
};
//将参数委托到指定方法执行
txtMessage.Invoke(actionDelegate, strClientSocket);
}
/// <summary>
/// 添加客户端到列表
/// </summary>
/// <param name="clientSocket"></param>
void addClientSocket(string strClientSocket)
{
//封装一个方法进行委托
Action<string> actionDelegate = (x) =>
{
//向列表中添加指定客户端套接字的远程终结点
lbOnlineClient.Items.Add(x.ToString());
};
//将参数委托到指定方法执行
txtMessage.Invoke(actionDelegate, strClientSocket);
}
/// <summary>
/// 跨线程显示接受到的数据
/// </summary>
/// <param name="socket"></param>
/// <param name="datas"></param>
/// <param name="length"></param>
void delegateShowReceiveData(Socket socket, Byte[] datas, int length)
{
//封装一个方法进行委托
Action<string> actionDelegate = (x) =>
{
//向文本框追加文本
txtMessage.AppendText(System.DateTime.Now.ToString()+ " -> "+ x.ToString() + "\r\n");
txtMessage.ScrollToCaret();
};
//将参数委托到指定方法执行
txtMessage.Invoke(actionDelegate, "收到来自 " + socket.RemoteEndPoint.ToString() + " 的数据:" + getStringFormByte(datas, length));
}
/// <summary>
/// 跨线程显示数据
/// </summary>
/// <param name="message"></param>
void delegateShowMseeage(string message)
{
//封装一个方法进行委托
Action<string> actionDelegate = (x) =>
{
if (txtMessage.Text.Length > 2000000)
txtMessage.Text = string.Empty;
//向文本框追加文本
txtMessage.AppendText(System.DateTime.Now.ToString()+" -> " + x.ToString() + "\r\n");
txtMessage.ScrollToCaret();
};
//将参数委托到指定方法执行
txtMessage.Invoke(actionDelegate, message);
}
/// <summary>
/// 显示数据流量
/// </summary>
void showDataFlow()
{
//封装一个方法进行委托
Action<string> actionDelegateShowFlow = (x) =>
{
lblDataFlow.Text = x.ToString();
};
//将参数委托到指定方法执行
lblDataFlow.Invoke(actionDelegateShowFlow, numDataFlow.ToString());
}
/// <summary>
/// 显示数据
/// </summary>
/// <param name="message"></param>
void showMesssge(string message)
{
//向文本框追加文本
txtMessage.AppendText(System.DateTime.Now.ToString() + " -> " + message + "\r\n");
txtMessage.ScrollToCaret();
}
/// <summary>
/// 16进制的字符串形式
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
string getStringFormByte(byte[] data, int length)
{
string str = "";
for (int i = 0; i < length; i++)
{
str += data[i].ToString("X").PadLeft(2, '0') + ' ';
}
return str;
}
}
/// <summary>
/// 发送数据的参数
/// </summary>
class dataSendArgsMode
{
/// <summary>
/// 套接字
/// </summary>
public Socket sockets;
/// <summary>
/// 数据
/// </summary>
public byte[] datas;
/// <summary>
/// 长度
/// </summary>
public int length;
}
}
c#tcp多线程服务器实例代码的更多相关文章
- C# TCP多线程服务器示例
前言 之前一直很少接触多线程这块.这次项目中刚好用到了网络编程TCP这块,做一个服务端,需要使用到多线程,所以记录下过程.希望可以帮到自己的同时能给别人带来一点点收获- 关于TCP的介绍就不多讲,神马 ...
- 【unix网络编程第三版】阅读笔记(四):TCP客户/服务器实例
本篇博客主要记录一个完整的TCP客户/服务器实例的编写,以及从这个实例中引发的对僵死进程的处理等问题. 1. TCP客户/服务器功能需求 本实例完成以下功能: (1) 客户从标准输入读入一行文本,并写 ...
- 套接字TCP控制台服务器程序代码示范
套接字TCP控制台服务器程序代码示范 https://blog.csdn.net/txwtech/article/details/90344081
- UDP和多线程服务器
UDP: UDP是数据报文传输协议,这个传输协议比较野蛮,发送端不需要理会接收端是否存在,直接就发送数据,不会像TCP协议一样建立连接.如果接收端不存在的话,发送的数据就会丢失,UDP协议不会去理会数 ...
- java多线程编程实例
[转]这篇文章主要介绍了java多线程编程实例,分享了几则多线程的实例代码,具有一定参考价值,加深多线程编程的理解还是很有帮助的,需要的朋友可以参考下. 1.三个售票窗口同时出售20张票程序分析: ...
- TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式
通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...
- TCP通信 - 服务器开启多线程与read()导致服务器阻塞问题
TCP通信的文件上传案例 本地流:客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流 网络流:客户端和服务器之间读写,必须使用Socket中提供的字节流对象 客户端工作:读取本地文件,上传到服 ...
- TCP通信的客户端代码实现和TCP通信的服务器代码实现
TCP通信的客户端代码实现 package com.yang.Test.ServerStudy; import java.io.*; import java.net.Socket; /** * TCP ...
- 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例
TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write -- ...
随机推荐
- thinkphp操作phpexcel问题
一.thinkphp引入PHPExcel到/Thinkphp/Library/Vendor/ 二.在控制器中引用 public function get_detail() { Vendor(" ...
- gulp插件学习01
1.安装和使用 安装node环境:官网:https://nodejs.org: 命令行输入 npm i gulp -g ,gulp-v查看安装是否成功: 创建项目目录: 进入目录,并在目录中按住shi ...
- 实时(RTC)时钟,系统时钟和CPU时钟
最近在学stm32的时候看到RTC时钟和系统时钟,不知道区别在哪里,于是上网查了一下. 实时时钟:RTC时钟,用于提供年.月.日.时.分.秒和星期等的实时时间信息,由后备电池供电,当你晚上关闭系统和早 ...
- python 读取矢量文件
#导入包 from osgeo import ogr #打开文件(False - read only, True - read/write) filename = "文件名.shp" ...
- 自定Tinymce中的图片上传
在引入组件上添加 上传图片的url地址 <tinymce :height="300" ref="tinymce" //上传图片的url地址 upload- ...
- elasticsearch kibana的安装部署与简单使用(一)
1.先说说es 我早两年使用过es5.x的版本,记得当时部署还是很麻烦,因为es是java写的,要先在机器上部署java环境jvm之类的一堆东西,然后才能安装es 但是现在我使用的是目前最新的7.6版 ...
- sqli-labs之Page-2
第二十一关:base64编码的cooki注入 YOUR COOKIE : uname = YWRtaW4= and expires: Tue 10 Mar 2020 - 03:42:09 注:YWRt ...
- Struts2-Tiles 2.5.2 升级指南和通配符拓展
最近工程从Struts2.3.18升级Struts2.5.2导致相关联的插件都需要升级到相同版本,其中tiles的变化最大. 1.web.xml上 listener org.apache.struts ...
- java -> final与static 关键字
final的概念 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这些特殊类之后,就可以对 ...
- 【雕爷学编程】Arduino动手做(60)---WS2812直条8位模块
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...