11 Commits

Author SHA1 Message Date
1ee59b6417 修改版本为1.0.3 2023-08-02 11:48:23 +08:00
a4a80afe73 1.修改依赖库的Framework版本为4.5.2
2.修复部分逻辑的crash问题
3.提升版本号为1.0.3
2023-08-02 11:41:24 +08:00
aa3482f033 更新 'README.md' 2023-07-06 19:35:26 +08:00
c611622a63 更新 'README.md' 2023-07-06 19:26:31 +08:00
640b568e28 更新 'README.md' 2023-07-06 19:18:54 +08:00
87815d5bf6 修改 copyright信息为 2023 2023-04-21 18:27:21 +08:00
fdfd1872f4 修改版本号为 1.0.2 2023-04-21 18:07:20 +08:00
f07832d5f2 优化wss链接问题 2023-04-21 18:00:46 +08:00
1572f31a45 修改版本号 2022-09-01 20:06:36 +08:00
d798e87abe 优化部分设置 2022-08-31 10:33:30 +08:00
7fd2e915ef wss 增加tls 版本 2022-06-08 19:33:45 +08:00
8 changed files with 216 additions and 41 deletions

View File

@@ -2,4 +2,9 @@
#### 介绍 #### 介绍
WebSocket测试工具 WebSocket测试工具, 后续逐步增加功能。
功能列表:
- [x] ws/wss链接发送消息
- [x] 定时 ping

View File

@@ -1,9 +1,12 @@
using System; using System;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Timers; using System.Timers;
using log4net; using log4net;
using WebSocketSharp; using WebSocketSharp;
using WebSocketTool.Base; using WebSocketTool.Base;
using WebSocketTool.Util; using WebSocketTool.Util;
using WebSocketTool.View.Dialog;
using LogManager = log4net.LogManager; using LogManager = log4net.LogManager;
namespace WebSocketTool.Client namespace WebSocketTool.Client
@@ -52,9 +55,59 @@ namespace WebSocketTool.Client
} }
} }
#region Proxy
private string proxyAddress;
private string proxyUserName;
private string proxyPassword;
public string ProxyAddress
{
get => proxyAddress;
set
{
proxyAddress = value;
RaisePropertyChanged(nameof(ProxyAddress));
}
}
public string ProxyUserName
{
get => proxyUserName;
set
{
proxyUserName = value;
RaisePropertyChanged(nameof(ProxyUserName));
}
}
public string ProxyPassword
{
get => proxyPassword;
set
{
proxyPassword = value;
RaisePropertyChanged(nameof(ProxyPassword));
}
}
private bool isProxyChecked;
public bool IsProxyChecked
{
get => isProxyChecked;
set
{
isProxyChecked = value;
RaisePropertyChanged(nameof(IsProxyChecked));
}
}
#endregion
public void Connect() public void Connect()
{ {
if (string.IsNullOrEmpty(WsUrl)) if (string.IsNullOrEmpty(WsUrl) || (!WsUrl.StartsWith("wss://") && !WsUrl.StartsWith("ws://")))
{ {
view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n 请输入正确的WebSocket地址"); view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n 请输入正确的WebSocket地址");
return; return;
@@ -72,6 +125,19 @@ namespace WebSocketTool.Client
} }
view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n Start Connect Socket"); view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n Start Connect Socket");
if (IsProxyChecked)
{
if (!string.IsNullOrEmpty(ProxyAddress))
{
view.AppendInfo($"Hint use proxy: {ProxyAddress}");
mClient.SetHttpProxy(ProxyAddress, ProxyUserName, ProxyPassword);
}
else
{
view.ShowToast("请输入代理地址!");
view.AppendInfo($"use proxy address is empty!");
}
}
mClient.ConnectAsync(); mClient.ConnectAsync();
} }
@@ -142,7 +208,14 @@ namespace WebSocketTool.Client
return; return;
} }
pingTimer = new Timer {Interval = PingTime, AutoReset = false}; if (PingTime <= 0)
{
view.AppendInfo("ping time interval must > 0");
return;
}
pingTimer = new Timer {Interval = PingTime, AutoReset = true};
pingTimer.Enabled = true;
pingTimer.Elapsed += (s, e) => pingTimer.Elapsed += (s, e) =>
{ {
Ping(); Ping();
@@ -159,7 +232,7 @@ namespace WebSocketTool.Client
public void StopPing() public void StopPing()
{ {
view.AppendInfo($"You {TimeUtil.GetCurrentDateTime()} \n StopPing"); App.RunOnUIThread(() => view.AppendInfo($"You {TimeUtil.GetCurrentDateTime()} \n StopPing"));
if (pingTimer != null) if (pingTimer != null)
{ {
pingTimer.Stop(); pingTimer.Stop();
@@ -171,10 +244,39 @@ namespace WebSocketTool.Client
{ {
view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n InitSocketClient"); view.AppendInfo($"Hint {TimeUtil.GetCurrentDateTime()} \n InitSocketClient");
mClient = new SocketClient(WsUrl); mClient = new SocketClient(WsUrl);
if (WsUrl.StartsWith("wss:"))
{
mClient.SetServerCertificateValidationCallback(CertificateValidationCallback);
}
mClient.OpenEvent += ClientOnOpenEvent; mClient.OpenEvent += ClientOnOpenEvent;
mClient.CloseEvent += ClientOnCloseEvent; mClient.CloseEvent += ClientOnCloseEvent;
mClient.ErrorEvent += ClientOnErrorEvent; mClient.ErrorEvent += ClientOnErrorEvent;
mClient.MessageEvent += ClientOnMessageEvent; mClient.MessageEvent += ClientOnMessageEvent;
if (IsProxyChecked)
{
mClient.SetHttpProxy(ProxyAddress, ProxyUserName, ProxyPassword);
}
}
private bool CertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
App.RunOnUIThread(() => { view.AppendInfo($"ServerCertificateError:{errors}"); });
Log.Info($"error:{errors}");
Log.Info($"Issuer: {certificate.Issuer},Subject:{certificate.Subject}");
Log.Info("ChainStatus:");
foreach (var status in chain.ChainStatus)
{
Log.Info($"{status.StatusInformation}: {status}");
}
Log.Info("ChainElements:");
foreach (var element in chain.ChainElements)
{
Log.Info($"element: {element.Certificate},{element.Information}");
}
return errors == SslPolicyErrors.None;
} }
private void ClientOnMessageEvent(object sender, MessageEventArgs e) private void ClientOnMessageEvent(object sender, MessageEventArgs e)

View File

@@ -11,6 +11,7 @@
<Grid Margin="5"> <Grid Margin="5">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="36"/> <RowDefinition Height="36"/>
<RowDefinition Height="40"/>
<RowDefinition Height="120"/> <RowDefinition Height="120"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
@@ -27,8 +28,31 @@
<Button x:Name="DisconnectBtn" Grid.Column="2" Content="断开" Click="DisconnectBtn_OnClick" Width="80" Height="32" <Button x:Name="DisconnectBtn" Grid.Column="2" Content="断开" Click="DisconnectBtn_OnClick" Width="80" Height="32"
HorizontalAlignment="Center" VerticalAlignment="Center" Cursor="Hand" IsEnabled="{Binding IsCloseEnable, Mode=OneWay}"/> HorizontalAlignment="Center" VerticalAlignment="Center" Cursor="Hand" IsEnabled="{Binding IsCloseEnable, Mode=OneWay}"/>
</Grid> </Grid>
<Grid Grid.Row="1" VerticalAlignment="Center" Height="32" Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="64"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="代理地址:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" VerticalAlignment="Center" Height="32" VerticalContentAlignment="Center"
Text="{Binding ProxyAddress}"/>
<TextBlock Grid.Column="2" Text="用户名:" VerticalAlignment="Center" Margin="4,0,0,0"/>
<TextBox Grid.Column="3" VerticalAlignment="Center" Height="32" VerticalContentAlignment="Center"
Text="{Binding ProxyUserName}"/>
<TextBlock Grid.Column="4" Text="密码:" VerticalAlignment="Center" Margin="4,0,0,0"/>
<TextBox Grid.Column="5" VerticalAlignment="Center" Height="32" VerticalContentAlignment="Center"
Text="{Binding ProxyPassword}"/>
<CheckBox x:Name="ProxyCb" Grid.Column="6" Content="代理" HorizontalAlignment="Right" VerticalAlignment="Center"
IsChecked="{Binding IsProxyChecked}"/>
</Grid>
<Grid x:Name="OperateGrid" Grid.Row="1" Margin="0,10,0,0"> <Grid x:Name="OperateGrid" Grid.Row="2" Margin="0,10,0,0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/> <ColumnDefinition Width="200"/>
@@ -55,7 +79,7 @@
</Grid> </Grid>
</Grid> </Grid>
<TextBox x:Name="InfoTb" Grid.Row="2" Margin="0,10,0,0" TextWrapping="Wrap" <TextBox x:Name="InfoTb" Grid.Row="3" Margin="0,10,0,0" TextWrapping="Wrap"
HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"/> HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"/>
</Grid> </Grid>
</Window> </Window>

View File

@@ -75,11 +75,18 @@ namespace WebSocketTool.Client
{ {
viewModel.Close(); viewModel.Close();
} }
public Window GetWindow()
{
return this;
}
} }
public interface IClientView public interface IClientView
{ {
void ShowToast(string msg); void ShowToast(string msg);
void AppendInfo(string info); void AppendInfo(string info);
Window GetWindow();
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Net.Security;
using System.Security.Authentication; using System.Security.Authentication;
using System.Text; using System.Text;
using log4net; using log4net;
@@ -14,11 +15,13 @@ namespace WebSocketTool.Client
public event EventHandler<MessageEventArgs> MessageEvent; public event EventHandler<MessageEventArgs> MessageEvent;
public event EventHandler<ErrorEventArgs> ErrorEvent; public event EventHandler<ErrorEventArgs> ErrorEvent;
public event EventHandler<EventArgs> OpenEvent; public event EventHandler<EventArgs> OpenEvent;
public event EventHandler<CloseEventArgs> CloseEvent; public event EventHandler<CloseEventArgs> CloseEvent;
public string Url { get; private set; }
public SocketClient(string url) public SocketClient(string url)
{ {
Log.Info($"create socket:{url}"); Log.Info($"create socket:{url}");
Url = url;
mSocket = new WebSocket(url); mSocket = new WebSocket(url);
if (url.StartsWith("wss")) if (url.StartsWith("wss"))
{ {
@@ -30,6 +33,35 @@ namespace WebSocketTool.Client
mSocket.OnMessage += OnMessage; mSocket.OnMessage += OnMessage;
} }
#region Config
public SocketClient SetServerCertificateValidationCallback(RemoteCertificateValidationCallback callback)
{
Log.Info("SetServerCertificateValidationCallback");
mSocket.SslConfiguration.ServerCertificateValidationCallback += callback;
return this;
}
public SocketClient SetEnableSslProtocols(SslProtocols protocols)
{
Log.Info($"SetEnableSslProtocols:{protocols}");
mSocket.SslConfiguration.EnabledSslProtocols = protocols;
return this;
}
public SocketClient SetHttpProxy(string address, string userName, string password)
{
Log.Info($"SetHttpProxy, address:{address}, userName:{userName}, password:{password}");
if (address.StartsWith("http://"))
{
mSocket.SetProxy(address, userName, password);
}
return this;
}
#endregion
#region Event Handler
private void OnMessage(object sender, MessageEventArgs e) private void OnMessage(object sender, MessageEventArgs e)
{ {
Log.Info($"OnMessage, isPing:{e.IsPing}, isText:{e.IsText}, isBinary:{e.IsBinary}, data:{e.Data}, rawData:{e.RawData.Length}"); Log.Info($"OnMessage, isPing:{e.IsPing}, isText:{e.IsText}, isBinary:{e.IsBinary}, data:{e.Data}, rawData:{e.RawData.Length}");
@@ -53,7 +85,40 @@ namespace WebSocketTool.Client
Log.Info("OnOpen"); Log.Info("OnOpen");
OpenEvent?.Invoke(this, e); OpenEvent?.Invoke(this, e);
} }
#endregion
#region State
public bool IsAlive()
{
Log.Info($"IsAlive:{mSocket?.IsAlive ?? false}");
return mSocket?.IsAlive ?? false;
}
#endregion
#region Operate
public void Connect()
{
Log.Info("Connect");
mSocket.Connect();
}
public void ConnectAsync()
{
Log.Info("ConnectAsync");
mSocket.ConnectAsync();
}
public void Send(string content)
{
Log.Info($"send:{content}");
if (content == null)
{
Log.Error("content is null!");
return;
}
mSocket.Send(content);
}
public void Ping(string msg = null) public void Ping(string msg = null)
{ {
Log.Info($"ping:{msg}"); Log.Info($"ping:{msg}");
@@ -67,35 +132,6 @@ namespace WebSocketTool.Client
} }
} }
public void Send(string content)
{
Log.Info($"send:{content}");
if (content == null)
{
Log.Error("content is null!");
return;
}
mSocket.Send(content);
}
public bool IsAlive()
{
Log.Info($"IsAlive:{mSocket?.IsAlive ?? false}");
return mSocket?.IsAlive ?? false;
}
public void Connect()
{
Log.Info("Connect");
mSocket.Connect();
}
public void ConnectAsync()
{
Log.Info("ConnectAsync");
mSocket.ConnectAsync();
}
public void Close() public void Close()
{ {
Log.Info("Close"); Log.Info("Close");
@@ -107,5 +143,6 @@ namespace WebSocketTool.Client
Log.Info("CloseAsync"); Log.Info("CloseAsync");
mSocket.CloseAsync(); mSocket.CloseAsync();
} }
#endregion
} }
} }

View File

@@ -12,7 +12,7 @@ using System.Windows;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DevWiki")] [assembly: AssemblyCompany("DevWiki")]
[assembly: AssemblyProduct("WebSocketTool")] [assembly: AssemblyProduct("WebSocketTool")]
[assembly: AssemblyCopyright("Copyright DevWiki © 2022")] [assembly: AssemblyCopyright("Copyright DevWiki © 2023")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@@ -51,5 +51,5 @@ using System.Windows;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示: //通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.3")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.3")]

View File

@@ -1,4 +1,4 @@
set version=1.0.0 set version=1.0.3
if not "%~1"=="" ( if not "%~1"=="" (
set version=%1 set version=%1

View File

@@ -9,7 +9,7 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>WebSocketSharp</RootNamespace> <RootNamespace>WebSocketSharp</RootNamespace>
<AssemblyName>websocket-sharp</AssemblyName> <AssemblyName>websocket-sharp</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>websocket-sharp.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>websocket-sharp.snk</AssemblyOriginatorKeyFile>
<FileUpgradeFlags> <FileUpgradeFlags>