add chatserver & client
This commit is contained in:
283
Project/ChatClientService.cs
Normal file
283
Project/ChatClientService.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
/// <summary>
|
||||
/// Background chat client service with auto-reconnect
|
||||
/// </summary>
|
||||
public class ChatClientService : IDisposable
|
||||
{
|
||||
private TcpClient tcpClient;
|
||||
private NetworkStream stream;
|
||||
private Thread receiveThread;
|
||||
private Thread reconnectThread;
|
||||
private bool isRunning;
|
||||
private bool isConnected;
|
||||
|
||||
private string serverIp;
|
||||
private int serverPort;
|
||||
private string nickName;
|
||||
private string employeeId;
|
||||
private string hostName;
|
||||
private string userGroup;
|
||||
|
||||
/// <summary>Connection status changed event</summary>
|
||||
public event EventHandler<bool> ConnectionStatusChanged;
|
||||
|
||||
/// <summary>Message received event</summary>
|
||||
public event EventHandler<ChatMessage> MessageReceived;
|
||||
|
||||
/// <summary>Connection status</summary>
|
||||
public bool IsConnected => isConnected;
|
||||
|
||||
/// <summary>User nickname</summary>
|
||||
public string NickName => nickName;
|
||||
|
||||
/// <summary>User employee ID</summary>
|
||||
public string EmployeeId => employeeId;
|
||||
|
||||
/// <summary>User group</summary>
|
||||
public string UserGroup => userGroup;
|
||||
|
||||
public ChatClientService(string serverIp, int serverPort)
|
||||
{
|
||||
this.serverIp = serverIp;
|
||||
this.serverPort = serverPort;
|
||||
this.hostName = System.Net.Dns.GetHostName();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start background service
|
||||
/// </summary>
|
||||
public void Start(string nickName, string employeeId, string userGroup)
|
||||
{
|
||||
if (isRunning)
|
||||
return;
|
||||
|
||||
this.nickName = nickName;
|
||||
this.employeeId = employeeId;
|
||||
this.userGroup = userGroup;
|
||||
isRunning = true;
|
||||
|
||||
// Start reconnect thread
|
||||
reconnectThread = new Thread(ReconnectLoop)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "ChatReconnectThread"
|
||||
};
|
||||
reconnectThread.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop background service
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
Disconnect();
|
||||
|
||||
try
|
||||
{
|
||||
reconnectThread?.Join(2000);
|
||||
receiveThread?.Join(2000);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto-reconnect loop
|
||||
/// </summary>
|
||||
private void ReconnectLoop()
|
||||
{
|
||||
while (isRunning)
|
||||
{
|
||||
if (!isConnected)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connect();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Retry after 5 seconds
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to server
|
||||
/// </summary>
|
||||
private void Connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
tcpClient = new TcpClient();
|
||||
tcpClient.Connect(serverIp, serverPort);
|
||||
stream = tcpClient.GetStream();
|
||||
isConnected = true;
|
||||
|
||||
// Notify connection status
|
||||
ConnectionStatusChanged?.Invoke(this, true);
|
||||
|
||||
// Send connect message
|
||||
var connectMsg = new ChatMessage
|
||||
{
|
||||
Type = MessageType.Connect,
|
||||
NickName = nickName,
|
||||
EmployeeId = employeeId,
|
||||
HostName = hostName,
|
||||
UserGroup = userGroup,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
SendMessage(connectMsg);
|
||||
|
||||
// Start receive thread
|
||||
receiveThread = new Thread(ReceiveLoop)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "ChatReceiveThread"
|
||||
};
|
||||
receiveThread.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Disconnect();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from server
|
||||
/// </summary>
|
||||
private void Disconnect()
|
||||
{
|
||||
if (!isConnected)
|
||||
return;
|
||||
|
||||
isConnected = false;
|
||||
|
||||
try
|
||||
{
|
||||
stream?.Close();
|
||||
tcpClient?.Close();
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Notify connection status
|
||||
ConnectionStatusChanged?.Invoke(this, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message receive loop
|
||||
/// </summary>
|
||||
private void ReceiveLoop()
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
|
||||
try
|
||||
{
|
||||
while (isRunning && isConnected && tcpClient.Connected)
|
||||
{
|
||||
int bytesRead = stream.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
// Connection closed
|
||||
break;
|
||||
}
|
||||
|
||||
string jsonData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
||||
var message = JsonConvert.DeserializeObject<ChatMessage>(jsonData);
|
||||
|
||||
if (message != null)
|
||||
{
|
||||
// Filter messages by group (dev can see all)
|
||||
// UserListResponse and system messages should always be received
|
||||
if (userGroup == "dev" ||
|
||||
message.UserGroup == userGroup ||
|
||||
message.Type == MessageType.Notice ||
|
||||
message.Type == MessageType.UserListResponse ||
|
||||
message.Type == MessageType.Pong)
|
||||
{
|
||||
MessageReceived?.Invoke(this, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Connection error
|
||||
}
|
||||
finally
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send message
|
||||
/// </summary>
|
||||
public bool SendMessage(ChatMessage message)
|
||||
{
|
||||
if (!isConnected || tcpClient == null || !tcpClient.Connected)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
message.NickName = nickName;
|
||||
message.UserGroup = userGroup;
|
||||
message.Timestamp = DateTime.Now;
|
||||
|
||||
string jsonData = JsonConvert.SerializeObject(message);
|
||||
byte[] data = Encoding.UTF8.GetBytes(jsonData);
|
||||
stream.Write(data, 0, data.Length);
|
||||
stream.Flush();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send chat message
|
||||
/// </summary>
|
||||
public bool SendChatMessage(string content)
|
||||
{
|
||||
var message = new ChatMessage
|
||||
{
|
||||
Type = MessageType.Chat,
|
||||
Content = content
|
||||
};
|
||||
return SendMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request user list
|
||||
/// </summary>
|
||||
public bool RequestUserList()
|
||||
{
|
||||
var message = new ChatMessage
|
||||
{
|
||||
Type = MessageType.UserListRequest
|
||||
};
|
||||
return SendMessage(message);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user