You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
12 KiB
C#

3 years ago
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
namespace SocketStudy.ServerApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//服务监听
private TcpListener _tcpServer = null;
//存放活动客户端连接字典
private ConcurrentDictionary<string, TcpClient> _remoteClientDic = new ConcurrentDictionary<string, TcpClient>();
//监听线程
private Thread _listenerThread;
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// 窗口呈现完毕事件
/// </summary>
private void Window_ContentRendered(object sender, EventArgs e)
{
//初始化客户端
comboBox_Clients.Items.Clear();
comboBox_Clients.Items.Insert(insertIndex: 0,"广播");
comboBox_Clients.SelectedIndex = 0;
//默认服务器网址
comboBox_ServerAddress.Items.Insert(0, "本机所有IP4");
comboBox_ServerAddress.SelectedIndex = 0;
var ip4Addresses = Dns.GetHostAddresses(Dns.GetHostName(), AddressFamily.InterNetwork) ?? new IPAddress[] { IPAddress.Any};
foreach (var ip in ip4Addresses)
{
comboBox_ServerAddress.Items.Add(ip);
}
}
/// <summary>
/// 启动服务
/// </summary>
private void btn_Start_Click(object sender, RoutedEventArgs e)
{
if (_tcpServer?.Server?.IsBound ?? false)
{
WriteLog("服务正在运行,无需启动!");
return;
}
IPAddress serverAddress = IPAddress.Any;
if (comboBox_ServerAddress.SelectedValue.ToString() != "本机所有IP4")
{
serverAddress = (IPAddress)comboBox_ServerAddress.SelectedValue;
}
int serverPort = 6605;
if (!int.TryParse(textBox_ServerPort.Text.Trim(), out serverPort))
{
WriteLog("端口号错误");
return;
}
else
{
if (serverPort <= 1024 || serverPort >= 65535)
{
WriteLog("端口号错误:必须在 1205-65534");
return;
}
}
WriteLog("启动服务...");
_tcpServer = new TcpListener(serverAddress, serverPort);
_tcpServer.Start();
WriteLog("服务成功启动!");
//开启监听线程
_listenerThread = new Thread(AcceptTcpClient);
_listenerThread.IsBackground = true;
_listenerThread.Start(_tcpServer);
//控件操作
comboBox_ServerAddress.IsEnabled = false;
textBox_ServerPort.IsEnabled = false;
WriteLog("服务启动完毕!");
}
/// <summary>
/// 停止服务
/// </summary>
private void btn_Stop_Click(object sender, RoutedEventArgs e)
{
if (_tcpServer == null || _tcpServer.Server.IsBound == false)
{
WriteLog("服务正未运行,无法停止!");
return;
}
//关闭客户端
foreach (var item in _remoteClientDic)
{
if (item.Value.Connected)
{
item.Value.Close();
item.Value.Dispose();
}
}
WriteLog("停止服务...");
_tcpServer?.Stop();
//清空客户端
_remoteClientDic.Clear();
ResetClientsItems();
//恢复控制状态
comboBox_ServerAddress.IsEnabled = true;
textBox_ServerPort.IsEnabled = true;
WriteLog("服务停止完成!");
}
/// <summary>
/// 发送数据
/// </summary>
private void btn_Send_Click(object sender, RoutedEventArgs e)
{
if (_remoteClientDic.Count == 0 || comboBox_Clients.Items.Count ==0)
{
WriteLog("没有正在连接的客户端,请先使用客户端连接到本服务器!");
return;
}
var clientForSend=new List<TcpClient>();
var selectedItemValue = comboBox_Clients.SelectedValue as string;
if (selectedItemValue == "广播")
{
clientForSend = _remoteClientDic.Where(q => q.Value.Connected == true).Select(d => d.Value).ToList();
}
else
{
var queryItem = _remoteClientDic.FirstOrDefault(q => q.Key == comboBox_Clients.SelectedValue.ToString());
clientForSend.Add(queryItem.Value);
}
foreach (var client in clientForSend)
{
try
{
var message = textBox_SendData.Text.Trim();
byte[] buffer = Encoding.UTF8.GetBytes(message);
NetworkStream networkStream = client.GetStream();
networkStream.Write(buffer, 0, buffer.Length);
WriteLog($"发送数据成功:{message}");
}
catch (Exception ex)
{
WriteLog($"{ex.Message}");
}
finally
{
}
}
}
/// <summary>
/// 写日志信息
/// </summary>
private void WriteLog(string message)
{
Dispatcher.BeginInvoke(new Action(() =>
{
richTextBox_Log.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {message}{System.Environment.NewLine}");
richTextBox_Log.ScrollToEnd();
Console.WriteLine(message);
}));
}
/// <summary>
/// 重新设置客户端列表项
/// </summary>
private void ResetClientsItems()
{
Dispatcher.BeginInvoke(new Action(() =>
{
//字典中的远程客户端同步到下拉列表项
foreach (var clientItem in _remoteClientDic)
{
if (!comboBox_Clients.Items.Contains(clientItem.Key))
{
comboBox_Clients.Items.Add(clientItem.Key);
}
}
//从下拉项中移除已经下线的远程客户端
for (int i = 0; i < comboBox_Clients.Items.Count; i++)
{
var itemValue = comboBox_Clients.Items[i] as string;
if (itemValue == null)
{
continue;
}
if (itemValue.Contains("广播"))
{
continue;
}
if (!_remoteClientDic.ContainsKey(itemValue))
{
comboBox_Clients.Items.Remove(comboBox_Clients.Items[i]);
}
}
}));
}
/// <summary>
/// 监听客户端连接方法
/// </summary>
private void AcceptTcpClient(Object? tcpListener)
{
TcpListener? tcpServer = tcpListener as TcpListener;
if (tcpServer == null)
{
WriteLog("调用监听连接方法时参数为null将监听不到客户端连接");
return;
}
WriteLog("开始监听客户端连接...");
//无限循环:处理多个客户端连接
while (_tcpServer.Server.IsBound)
{
TcpClient remoteClientSocket = null;
try
{
//阻塞等待操作
remoteClientSocket = _tcpServer.AcceptTcpClient();
WriteLog("接收到连接请求...");
var remoteEndPoint = remoteClientSocket.Client.RemoteEndPoint as IPEndPoint;
if (remoteEndPoint == null)
{
continue;
}
string ipAndPortKey = $"{remoteEndPoint.Address}:{remoteEndPoint.Port}";
if (!_remoteClientDic.ContainsKey(ipAndPortKey))
{
_remoteClientDic.TryAdd(ipAndPortKey, remoteClientSocket);
}
ResetClientsItems();
//接收数据线程
Thread receviceThread = new Thread(ReciveData);
receviceThread.IsBackground = true;
receviceThread.Start(remoteClientSocket);
WriteLog("连接请求处理完成!");
}
catch (SocketException socketException)
{
//移除客户端
remoteClientSocket?.Close();
remoteClientSocket?.Dispose();
WriteLog($"出现Socket异常{socketException.Message}");
}
catch (Exception ex)
{
//移除客户端
remoteClientSocket?.Close();
remoteClientSocket?.Dispose();
WriteLog($"出现异常:{ex.Message}");
}
finally
{
}
}
//清空客户端
_remoteClientDic.Clear();
ResetClientsItems();
WriteLog($"监听客户端连接的线程退出线程托管Id={Thread.CurrentThread.ManagedThreadId}");
}
/// <summary>
/// 接收客户端数据方法
/// </summary>
private void ReciveData(object? tcpClient)
{
if (tcpClient == null)
{
WriteLog($"接收数据出错:客户端参数{nameof(tcpClient)}为 null");
return;
}
TcpClient remoteClient = (TcpClient)tcpClient;
IPEndPoint? remoteEndPoint = remoteClient.Client?.RemoteEndPoint as IPEndPoint;
string remoteClientKey = $"{remoteEndPoint?.Address}:{remoteEndPoint?.Port}";
try
{
while (remoteClient.Connected)
{
NetworkStream remoteClientStream = remoteClient.GetStream();
byte[] buffer = new byte[8096];
//阻塞等待操作
var readCount = remoteClientStream.Read(buffer, 0, buffer.Length);
//为0代表客户端主动发送关闭操作数据。平常时即使发送0长度数据也不会是0
if (readCount == 0)
{
remoteClientStream.Close();
remoteClientStream.Dispose();
WriteLog($"接收[{remoteClientKey}]关闭连接请求数据。");
break;
}
var message = Encoding.UTF8.GetString(buffer, 0, readCount);
WriteLog($"接收到[{remoteClientKey}]数据:{message}");
}
}
catch (SocketException socketException)
{
WriteLog($"接收到[{remoteClientKey}]数据异常:{socketException.Message}");
}
catch (Exception ex)
{
WriteLog($"接收到[{remoteClientKey}]数据异常:{ex.Message}");
}
finally
{
remoteClient.Close();
remoteClient.Dispose();
_remoteClientDic.Remove(remoteClientKey, out var sss);
ResetClientsItems();
WriteLog($"接收[{remoteClientKey}]数据的线程退出线程托管Id={Thread.CurrentThread.ManagedThreadId}");
}
}
}
}