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多线程服务器实例代码的更多相关文章

  1. C# TCP多线程服务器示例

    前言 之前一直很少接触多线程这块.这次项目中刚好用到了网络编程TCP这块,做一个服务端,需要使用到多线程,所以记录下过程.希望可以帮到自己的同时能给别人带来一点点收获- 关于TCP的介绍就不多讲,神马 ...

  2. 【unix网络编程第三版】阅读笔记(四):TCP客户/服务器实例

    本篇博客主要记录一个完整的TCP客户/服务器实例的编写,以及从这个实例中引发的对僵死进程的处理等问题. 1. TCP客户/服务器功能需求 本实例完成以下功能: (1) 客户从标准输入读入一行文本,并写 ...

  3. 套接字TCP控制台服务器程序代码示范

    套接字TCP控制台服务器程序代码示范  https://blog.csdn.net/txwtech/article/details/90344081

  4. UDP和多线程服务器

    UDP: UDP是数据报文传输协议,这个传输协议比较野蛮,发送端不需要理会接收端是否存在,直接就发送数据,不会像TCP协议一样建立连接.如果接收端不存在的话,发送的数据就会丢失,UDP协议不会去理会数 ...

  5. java多线程编程实例

    [转]这篇文章主要介绍了java多线程编程实例,分享了几则多线程的实例代码,具有一定参考价值,加深多线程编程的理解还是很有帮助的,需要的朋友可以参考下. 1.三个售票窗口同时出售20张票程序分析:   ...

  6. TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式

    通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...

  7. TCP通信 - 服务器开启多线程与read()导致服务器阻塞问题

    TCP通信的文件上传案例 本地流:客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流 网络流:客户端和服务器之间读写,必须使用Socket中提供的字节流对象 客户端工作:读取本地文件,上传到服 ...

  8. TCP通信的客户端代码实现和TCP通信的服务器代码实现

    TCP通信的客户端代码实现 package com.yang.Test.ServerStudy; import java.io.*; import java.net.Socket; /** * TCP ...

  9. 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例

    TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write -- ...

随机推荐

  1. Day_08【面向对象】扩展案例4_年龄为30岁的老王养了一只黑颜色的2岁的宠物……

    #分析以下需求,并用代码实现: 1.定义动物类 属性: 年龄,颜色 行为: eat(String something)方法(无具体行为,不同动物吃的方式和东西不一样,something表示吃的东西) ...

  2. 【poj 2406】Power Strings 后缀数组DC3模板 【连续重复子串】

    Power Strings 题意 给出一个字符串s,求s最多由几个相同的字符串重复而成(最小循环节的重复次数) 思路 之前学习KMP的时候做过. 我的思路是:枚举字符串的长度,对于当前长度k,判断\( ...

  3. spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版

    spring-boot-cloud-module spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版. 新手上路的绝佳模版,只有必要的配 ...

  4. Velocity中判断表达式是不是为空

    Velocity中判断表达式是不是为空 $if ($null.isNull($mycoll) || $mycoll.size()==0) ${}与$!{}区别 例子: ${str}:如果str没有值, ...

  5. Anaconda3中的Jupyter notebook添加目录插件

    学习python和人工智能的相关课程时安装了Anaconda3,想在Jupyter notebook中归纳整理笔记,为了方便日后查找想安装目录(Table of Contents, TOC)插件,查找 ...

  6. .Net(c#)使用 Kafka 小结

    .Net(c#)使用 Kafka 小结 1.开篇 由于项目中必须使用 kafka 来作为消息组件,所以使用 kafka 有一段时间了.不得不感叹 kafka 是一个相当优秀的消息系统.下面直接对使用过 ...

  7. ios上表单默认样式

    摘自:http://blog.sina.com.cn/s/blog_7d796c0d0102uyd2.html 可惜不能直接转到博客园. input[type="button"], ...

  8. Form action 方法上传文件

    <form method="post" id="form1" runat="server" enctype="multipa ...

  9. php IE中文乱码

    echo mb_convert_encoding("你是我的朋友", "big5", "GB2312"); 详细出处参考:http://ww ...

  10. element-ui的el-table和el-form嵌套使用表单校验

    表格中嵌套使用表单验证 表格是el-table自动获取的后台数据,每行都有el-input的验证,这样一个rules的规则就不能匹配到每一行,所以要是用动态的prop和rules规则 需求如下,要对告 ...