TCP聊天室
服务器端
服务器界面设计xaml
<Window x:Class="ChatServer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Closed="Window_Closed" Loaded="Window_Loaded">
<Grid>
<Button Content="启动" Name="btnStart" HorizontalAlignment="Left" Margin="28,29,0,0" VerticalAlignment="Top" Width="105" Height="39" Click="btnStart_Click" />
<Button Content="停止" Name="btnStop" HorizontalAlignment="Left" Margin="193,29,0,0" VerticalAlignment="Top" Width="108" Height="39" Click="btnStop_Click" />
<TextBox Name="txtMsg" HorizontalAlignment="Left" Height="200" AcceptsReturn="True" Margin="28,98,0,0" IsReadOnly="True" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" Text="" VerticalAlignment="Top" Width="460"/>
</Grid>
</Window>后台实现
using System;
using System.Collections.Generic;
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.Sockets;
using System.Threading;
using System.IO;
namespace ChatServer
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//保存多个客户端的通信套接字
public static Dictionary<String, Socket> clientList = null;
//声明一个监听套接字
Socket serverSocket = null;
//设置一个监听标记
Boolean isListen = true;
private void btnStart_Click(object sender, RoutedEventArgs e)
{
if (serverSocket == null)
{
try
{
clientList = new Dictionary<string, Socket>();
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//实例监听套接字
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 8080);//端点
serverSocket.Bind(endPoint);//绑定
serverSocket.Listen(100);//设置最大连接数
Thread th = new Thread(StartListen);
th.IsBackground = true;
th.Start();
txtMsg.Dispatcher.BeginInvoke(new Action(() =>
{
txtMsg.Text += "服务启动...\r\n";
}));
}
catch (SocketException ex)
{
MessageBox.Show(ex.ToString());
}
}
}
//线程函数,封装一个建立连接的通信套接字
private void StartListen()
{
isListen = true;
Socket clientSocket = default(Socket);
while (isListen)
{
try
{
clientSocket = serverSocket.Accept();//这个方法返回一个通信套接字
}
catch (SocketException ex)
{
File.AppendAllText("E:\\Exception.txt", ex.ToString() + "\r\nStartListen\r\n" + DateTime.Now.ToString() + "\r\n");
}
Byte[] bytesFrom = new Byte[4096];
String dataFromClient = null;
if (clientSocket != null && clientSocket.Connected)
{
MessageBox.Show("接收到连接请求");
try
{
Int32 len = clientSocket.Receive(bytesFrom);//获取客户端发来的信息
if (len > -1)
{
String tmp = Encoding.UTF8.GetString(bytesFrom, 0, len);
try
{
dataFromClient =tmp;
}
catch (Exception ex)
{
}
Int32 sublen = dataFromClient.LastIndexOf("$");
if (sublen > -1)
{
dataFromClient = dataFromClient.Substring(0, sublen);
if (!clientList.ContainsKey(dataFromClient))
{
clientList.Add(dataFromClient, clientSocket);
BroadCast.PushMessage(dataFromClient + " Joined ", dataFromClient, false, clientList);
HandleClient client = new HandleClient();
client.StartClient(clientSocket, dataFromClient, clientList);
}
else
{
clientSocket.Send(Encoding.UTF8.GetBytes("#" + dataFromClient + "#"));
}
}
}
}
catch (Exception ex)
{
File.AppendAllText("E:\\Exception.txt", ex.ToString() + "\r\n\t\t" + DateTime.Now.ToString() + "\r\n");
}
}
}
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
if (serverSocket != null)
{
foreach (var socket in clientList.Values)
{
socket.Close();
}
clientList.Clear();
serverSocket.Close();
serverSocket = null;
isListen = false;
txtMsg.Text += "服务停止\r\n";
}
}
private void Window_Closed(object sender, EventArgs e)
{
isListen = false;
BroadCast.PushMessage("Server has closed", "", false, clientList);
clientList.Clear();
serverSocket.Close();
serverSocket = null;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
clientList = new Dictionary<string, Socket>();
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//实例监听套接字
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 8080);//端点
serverSocket.Bind(endPoint);//绑定
serverSocket.Listen(100);//设置最大连接数
Thread th = new Thread(StartListen);
th.IsBackground = true;
th.Start();
txtMsg.Dispatcher.BeginInvoke(new Action(() =>
{
txtMsg.Text += "服务启动...\r\n";
}));
}
catch (SocketException ex)
{
MessageBox.Show(ex.ToString());
}
}
}
//这里专门负责接收客户端发来的消息,并且转发给所有的客户端
public class HandleClient
{
Socket clientSocket;
String clNo;
Dictionary<String, Socket> clientList = new Dictionary<string, Socket>();
public void StartClient(Socket inClientSocket, String clientNo, Dictionary<String, Socket> cList)
{
clientSocket = inClientSocket;
clNo = clientNo;
clientList = cList;
Thread th = new Thread(Chat);
th.IsBackground = true;
th.Start();
}
private void Chat()
{
Byte[] bytesFromClient = new Byte[4096];
String dataFromClient;
String msgTemp = null;
Byte[] bytesSend = new Byte[4096];
Boolean isListen = true;
while (isListen)
{
try
{
Int32 len = clientSocket.Receive(bytesFromClient);
if (len > -1)
{
dataFromClient = Encoding.UTF8.GetString(bytesFromClient, 0, len);
if (!String.IsNullOrWhiteSpace(dataFromClient))
{
dataFromClient = dataFromClient.Substring(0, dataFromClient.LastIndexOf("$"));
if (!String.IsNullOrWhiteSpace(dataFromClient))
{
BroadCast.PushMessage(dataFromClient, clNo, true, clientList);
msgTemp = clNo + ": " + dataFromClient + "\t\t" + DateTime.Now.ToString();
String newMsg = msgTemp;
File.AppendAllText("E:\\MessageRecords.txt", newMsg + "\r\n", Encoding.UTF8);
}
else
{
isListen = false;
clientList.Remove(clNo);
clientSocket.Close();
clientSocket = null;
}
}
}
}
catch (Exception ex)
{
isListen = false;
clientList.Remove(clNo);
clientSocket.Close();
clientSocket = null;
File.AppendAllText("E:\\Exception.txt", ex.ToString() + "\r\nChat\r\n" + DateTime.Now.ToString() + "\r\n");
}
}
}
}
//向所有的客户端发送消息
public class BroadCast
{
public static void PushMessage(String msg, String uName, Boolean flag, Dictionary<String, Socket> clientList)
{
foreach (var item in clientList)
{
Socket brdcastSocket = (Socket)item.Value;
String msgTemp = null;
Byte[] castBytes = new Byte[4096];
if (flag == true)
{
msgTemp = uName + ": " + msg + "\t\t" + DateTime.Now.ToString();
castBytes = Encoding.UTF8.GetBytes(msgTemp);
}
else
{
msgTemp = msg + "\t\t" + DateTime.Now.ToString();
castBytes = Encoding.UTF8.GetBytes(msgTemp);
}
try
{
brdcastSocket.Send(castBytes);
}
catch (Exception ex)
{
brdcastSocket.Close();
brdcastSocket = null;
File.AppendAllText("E:\\Exception.txt", ex.ToString() + "\r\nPushMessage\r\n" + DateTime.Now.ToString() + "\r\n");
continue;
}
}
}
}
}
客户端
客户端界面设计xaml
<Window x:Class="ChatRoom.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Closed="Window_Closed_1" Activated="Window_Activated_1"
WindowStartupLocation="CenterScreen" >
<Window.Resources>
<RoutedUICommand x:Key="SendMessageShortcutKey" Text="Send Message Shortcut Key"></RoutedUICommand>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+Enter" Command="{StaticResource SendMessageShortcutKey}"></KeyBinding>
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource SendMessageShortcutKey}" CanExecute="CommandBinding_SendMessage_CanExecute" Executed="CommandBinding_SendMessage_Executed">
</CommandBinding>
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="250"></RowDefinition>
<RowDefinition Height="150"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Label Name="lbMsg" Content="设置你的用户名:" Margin="10,10"></Label>
<TextBox Name="txtName" Width="200" Height="30" FontSize="16"></TextBox>
<Button Name="btnConnect" Content="连接服务器" Width="100" Height="30" Margin="15,8" Click="btnConnect_Click"></Button>
</StackPanel>
<TextBox Grid.Row="1" Name="txtReceiveMsg" Margin="10,10.4,10.4,159.2" BorderBrush="DarkGreen" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Foreground="DarkBlue" IsReadOnly="True"></TextBox>
<TextBox Grid.Row="1" Name="txtSendMsg" Margin="10,99.4,9.4,0" AcceptsReturn="True" BorderBrush="DarkBlue" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Height="99" VerticalAlignment="Top"/>
<Button Grid.Row="1" Name="btnSend" Content="发送(Ctrl+Enter)" Width="100" Height="30" Click="btnSend_Click" RenderTransformOrigin="0.478,0.613" Margin="210,209.4,208.4,10.2"></Button>
</Grid>
</Window>
后台代码
using System;
using System.Collections.Generic;
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.Runtime.InteropServices;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace ChatRoom
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//窗口闪烁代码
public const UInt32 FLASHW_STOP = 0;
public const UInt32 FLASHW_CAPTION = 1;
public const UInt32 FLASHW_TRAY = 2;
public const UInt32 FLASHW_ALL = 3;
public const UInt32 FLASHW_TIMER = 4;
public const UInt32 FLASHW_TIMERNOFG = 12;
[DllImport("user32.dll")]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[DllImport("user32.dll")]
static extern bool FlashWindow(IntPtr handle, bool invert);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
Socket clientSocket = null;
static Boolean isListen = true;
private void btnSend_Click(object sender, RoutedEventArgs e)
{
SendMessage();
}
private void SendMessage()
{
if (String.IsNullOrWhiteSpace(txtSendMsg.Text.Trim()))
{
MessageBox.Show("发送内容不能为空哦~");
return;
}
if (clientSocket != null && clientSocket.Connected)
{
String sendMsg = txtSendMsg.Text + "$";
Byte[] bytesSend = Encoding.UTF8.GetBytes(sendMsg);
clientSocket.Send(bytesSend);
txtSendMsg.Text = "";
}
else
{
MessageBox.Show("未连接服务器或者服务器已停止,请联系管理员~");
return;
}
}
/// <summary>
/// 每一个连接的客户端必须设置一个唯一的用户名,在服务端是把用户名和通信套接字
/// 保存在Dictionary<UserName,ClientSocket>.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnConnect_Click(object sender, RoutedEventArgs e)
{
if (String.IsNullOrWhiteSpace(txtName.Text.Trim()))
{
MessageBox.Show("还是设置一个用户名吧,这样别人才能认识你哦~");
return;
}
if (clientSocket == null || !clientSocket.Connected)
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.BeginConnect(IPAddress.Loopback, 8080, (args) =>
{
if (args.IsCompleted)
{
Byte[] bytesSend = new Byte[4096];
txtName.Dispatcher.BeginInvoke(new Action(() =>
{
String tmp = txtName.Text.Trim() + "$";
bytesSend = Encoding.UTF8.GetBytes(tmp);
if (clientSocket != null && clientSocket.Connected)
{
clientSocket.Send(bytesSend);
txtName.IsEnabled = false;
txtSendMsg.Focus();
Thread th = new Thread(DataFromServer);
th.IsBackground = true;
th.Start();
}
else
{
MessageBox.Show("服务器已经关闭");
}
}));
}
}, null);
}
catch (SocketException ex)
{
MessageBox.Show(ex.ToString());
}
}
else
{
MessageBox.Show("You has already connected with Server");
}
}
private void ShowMsg(String msg)
{
txtReceiveMsg.Dispatcher.BeginInvoke(new Action(() =>
{
txtReceiveMsg.Text += Environment.NewLine + msg;
txtReceiveMsg.ScrollToEnd();
IntPtr handle = new System.Windows.Interop.WindowInteropHelper(this).Handle;
if (this.WindowState == WindowState.Minimized || handle != GetForegroundWindow())
{
FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
fInfo.hwnd = handle;
fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
fInfo.uCount = UInt32.MaxValue;
fInfo.dwTimeout = 0;
FlashWindowEx(ref fInfo);
}
}));
}
//获取服务端的消息
private void DataFromServer()
{
ShowMsg("Connected to the Chat Server...");
isListen = true;
try
{
while (isListen)
{
Byte[] bytesFrom = new Byte[4096];
Int32 len = clientSocket.Receive(bytesFrom);
String dataFromClientTmp = Encoding.UTF8.GetString(bytesFrom, 0, len);
if (!String.IsNullOrWhiteSpace(dataFromClientTmp))
{
String dataFromClient = dataFromClientTmp;
if (dataFromClient.StartsWith("#") && dataFromClient.EndsWith("#"))
{
String userName = dataFromClient.Substring(1, dataFromClient.Length - 2);
this.Dispatcher.BeginInvoke(new Action(() =>
{
MessageBox.Show("用户名:[" + userName + "]已经存在,请尝试其它用户名");
}));
isListen = false;
txtName.Dispatcher.BeginInvoke(new Action(() =>
{
txtName.IsEnabled = true;
clientSocket = null;
}));
}
else
{
ShowMsg(dataFromClient);
}
}
}
}
catch (SocketException ex)
{
isListen = false;
if (clientSocket != null && clientSocket.Connected)
{
//我没有在客户端关闭连接而是向服务端发送一个消息,在服务器端关闭,这样主要
//为了异常的处理放到服务端。客户端关闭会抛异常,服务端也会抛异常。
clientSocket.Send(Encoding.UTF8.GetBytes("$"));
MessageBox.Show(ex.ToString());
}
}
}
//这是定义了一个发送的快捷键,WPF的知识
private void CommandBinding_SendMessage_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (String.IsNullOrWhiteSpace(txtSendMsg.Text.Trim()))
{
e.CanExecute = false;
}
else
{
e.CanExecute = true;
}
}
private void CommandBinding_SendMessage_Executed(object sender, ExecutedRoutedEventArgs e)
{
SendMessage();
}
private void Window_Activated_1(object sender, EventArgs e)
{
txtSendMsg.Focus();
}
private void Window_Closed_1(object sender, EventArgs e)
{
if (clientSocket != null && clientSocket.Connected)
{
clientSocket.Send(Encoding.UTF8.GetBytes("$"));
}
}
}
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}
}
版权声明:
浙公网安备 33010602011771号