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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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}");
}
}
}
}