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 -- ...
随机推荐
- Markdown更改字体、颜色、大小,设置文字背景色,调整图片大小设置居中,插入表格等方法
Markdown 通过简单标记语法,使普通文本内容具有一定格式.但它本身不支持修改字体.字号与颜色等功能的. 一.更改字体大小.颜色.更改字体 Markdown语法 <font face=&qu ...
- CTR预估模型演变及学习笔记
[说在前面]本人博客新手一枚,象牙塔的老白,职业场的小白.以下内容仅为个人见解,欢迎批评指正,不喜勿喷![握手][握手] [再啰嗦一下]如果你对智能推荐感兴趣,欢迎先浏览我的另一篇随笔:智能推荐算法演 ...
- Day_13【IO流】扩展案例2_统计指定项目文件中字符出现的次数
需求分析 统计当前项目下info2.txt文件中, 每个字符出现的个数 文件内容如下: welcome to itheima!!! 最终效果如下: w(1) (2)!(3)t(2)e(3)c(1)a( ...
- JS字符串截取 “指定字符” 前面和后面的内容!
JS字符串截取 “指定字符” 前面和后面的内容! var string= "07/12" var before = string.split('/')[0] var after = ...
- angular foreach的使用
var myAppModule = angular.module('myApp', []); var values = { name : 'misko', gender : 'male', " ...
- java ->IO流_commons类
commons-IO 导入classpath 加入classpath的第三方jar包内的class文件才能在项目中使用 1.创建lib文件夹 2.将commons-io.jar拷贝到lib文件夹 3. ...
- Spring全家桶之spring boot(一)
spring boot框架抛弃了繁琐的xml配置过程,采用大量的默认配置简化我们的开发过程.使用spring boot之后就不用像以前使用ssm的时候添加那么多配置文件了,spring boot除了支 ...
- 类文件结构——深入理解Java虚拟机 笔记三
在之前的笔记中记录过,Java程序变成可执行文件的步骤是:源代码-->经过编译变成class文件-->经过JVM虚拟机变成可执行的二进制文件.因此,为了对JVM执行程序的过程有一个好的了解 ...
- Java POI 读取Excel数据转换为XML格式
1.首先要下载poi相关的包:http://poi.apache.org/ ,以下是所需的jar包 2.贴上详细的代码 public class ExcelToXml { /** * 将excel的 ...
- VIOS挂载ISO文件
6.VIOS挂载ISO文件 1.给vhost建立虚拟设备 mkvdev -vadapter vhostX -fbo -dev cdx 2.建立存放ISO的资料库 mkrep -sp rootvg -s ...