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 -- ...
随机推荐
- JAVA设计模式之组合模式(composite)
组合模式:树状结构专用模式 代码如下: package com.srr.dp.composite; import java.util.ArrayList; import java.util.List; ...
- MATLAB矩阵处理—特殊矩阵
需要掌握 MATLAB语言中特殊矩阵 MATLAB语言中矩阵的变幻 MATLAB语言矩阵如何求值 MATLAB语言中特征值与特征向量 MATLAB语言中稀疏矩阵 2.1 特殊矩阵 如何建立矩阵? 逐 ...
- k-modes聚类算法
为什么要用k-modes算法 k-means算法是一种简单且实用的聚类算法,但是传统的k-means算法只适用于连续属性的数据集(数值型数据),而对于离散属性的数据集,计算簇的均值以及点之间的欧式距离 ...
- python语法学习第十天--类与对象相关的BIF、魔法方法
一些相关的BIF: issubclass(class,classInfo)#判断是否为子类,classInfo可以为多个类的元组,其中一个是,返回true,一个类也被认为是自己的子类,object是所 ...
- [ACdream 1212 New Year Bonus Grant]贪心
题意:员工之间形成一棵树,上级可以给下级发奖金,任何一个人最多可以给一个下级发,并且发了奖金后就不能接受奖金.求总共最多可以产生多少的奖金流动 思路:每次选择没有下级并且有上级的员工a,令它的上级为b ...
- 腾讯面试居然跟我扯了半小时的CountDownLatch
一个长头发.穿着清爽的小姐姐,拿着一个崭新的Mac笔记本向我走来,看着来势汹汹,我心想着肯定是技术大佬吧!但是我也是一个才华横溢的人,稳住我们能赢. 面试官:看你简历上有写熟悉并发编程,CountDo ...
- shell 光标处理快捷键
Ctrl+左右键 单词之间跳转Ctrl+a跳到本行的行首, Ctrl+e则跳到页尾. Ctrl+u删除当前光标前面的文字 ctrl+k-删除当前光标后面的文字 Ctrl+w和Alt+d-对于当前的单词 ...
- tp5分页数据
paginate分页完成之后,生成的分页数据是对象形式存在的,所以如果要调用其分页的数据,比如想要遍历修改数据中的值,等需要进行 foreach操作的地方,需要使用 $re=Db::->tabl ...
- Docker学习笔记(二):端口映射与容器互联
端口映射 使用docker run时,可以指定-P(大写)与-p(小写)参数映射端口. docker run -P -P(大写)会随机映射一个端口到容器的内部端口 -> [feifei@ffma ...
- jQuery学习笔记——jQuery基础核心
代码风格 在jQuery程序中,不管是页面元素的选择.内置的功能函数,都是美元符号“$”来起始的.而这个“$”就是jQuery当中最重要且独有的对象:jQuery对象,所以我们在页面元素选择或执行功能 ...