1.界面XAML代码:
<StackPanel>
<Canvas Margin="10,20" Height="30">
<Label Content="IP:" Height="30" Width="30" FontSize="18" HorizontalContentAlignment="Center" ="8"/>
<TextBox x:Name="txtIp" Text="192.168.249.239" Height="30" Width="150" FontSize="20" HorizontalContentAlignment="Center" ="41" />
<Label Content="Port:" Height="30" Width="50" FontSize="18" HorizontalContentAlignment="Center" ="210"/>
<TextBox x:Name="txtPort" Text="45000" Height="30" Width="150" FontSize="20" HorizontalContentAlignment="Center" ="263" />
<Button x:Name="btnStartServer" Content="接服务段" Height="30" Width="100" ="460"/>
</Canvas>
<TextBox Name="txtLog" Height="300" AcceptsReturn="True" TextWrapping="Wrap"></TextBox>
<Canvas Margin="0,20" Height="30">
<TextBox x:Name="txtMsg" Height="30" Width="450" FontSize="20" HorizontalContentAlignment="Center" ="0" />
<Button x:Name="btnSendMsg" Content="发送消息" Height="30" Width="100" ="470" />
</Canvas>
</StackPanel>
2.后台代码:
using System;
using ;
using ;
using ;
using ;
using ;
namespace WPF_Client
{
/// <summary>
/// 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private Socket _socket;
public MainWindow()
{
InitializeComponent();
+= BtnSendMsg_Click;//注册事件
+= BtnConnect_Click;
Closing += ClientWindows_Closing;
}
/// <summary>
/// 窗口关闭事件
/// </summary>
private void ClientWindows_Closing(object sender, e)
{
ServerExit(null, _socket);//向服务端说我下线了。
}
/// <summary
/// 连接按钮事件
/// </summary>
private void BtnConnect_Click(object sender, RoutedEventArgs e)
{
//1、创建Socket对象
Socket socket = new Socket(, , );
_socket = socket;
//2、连接服务器,绑定IP 与 端口
IPEndPoint iPEndPoint = new IPEndPoint((), int.Parse());
try
{
(iPEndPoint);
("连接成功!", "提示");
}
catch (Exception)
{
("连接失败,请重新连接!", "提示");
return;
}
//3、接收消息
(new WaitCallback(ReceiveServerMsg), socket);
}
/// <summary>
/// 不断接收客户端信息子线程方法
/// </summary>
/// <param name="obj">参数Socke对象</param>
private void ReceiveServerMsg(object obj)
{
var proxSocket = obj as Socket;
//创建缓存内存,存储接收的信息 ,不能放到while中,这块内存可以循环利用
byte[] data = new byte[1020 * 1024];
while (true)
{
int len;
try
{
//接收消息,返回字节长度
len = (data, 0, , );
}
catch (Exception ex)
{
//7、关闭Socket
//异常退出
try
{
ServerExit(string.Format("服务端:{0}非正常退出", ()), proxSocket);
}
catch (Exception)
{
}
return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束
}
if (len <= 0)//判断接收的字节数
{
//7、关闭Socket
//小于0表示正常退出
try
{
ServerExit(string.Format("服务端:{0}正常退出", ()), proxSocket);
}
catch (Exception)
{
}
return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束
}
//将消息显示到TxtLog
string msgStr = (data, 0, len);
//拼接字符串
AppendTxtLogText(string.Format("接收到服务端:{0}的消息:{1}", (), msgStr));
}
}
/// <summary>
/// 客户端退出调用
/// </summary>
/// <param name="msg"></param>
private void ServerExit(string msg, Socket proxSocket)
{
AppendTxtLogText(msg);
try
{
if ()//如果是连接状态
{
();//关闭连接
(100);//100秒超时间
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 发送信息按钮事件
/// </summary>
private void BtnSendMsg_Click(object sender, RoutedEventArgs e)
{
byte[] data = (this.);
//6、发送消息
_socket.Send(data, 0, , ); //指定套接字的发送行为
this. = null;
}
/// <summary>
/// 向文本框中追加信息
/// </summary>
/// <param name="str"></param>
private void AppendTxtLogText(string str)
{
if (!(()))//判断跨线程访问
{
//异步方法
this.(new Action<string>(s =>
{
this. = string.Format("{0}\r\n{1}", s, );
}), str);
}
else
{
this. = string.Format("{0}\r\n{1}", str, );
}
}
}
}
- 首先在类里面声明一个byte数组(static byte[] b=new byte[1024];),用来存放客户端发送来的数据,数组的大小可以根据自己的需求填写,然后就写你本电脑的IP地址(获取电脑的IP地址方法:window键+R键,然后输入CMD回车键,再输入ipconfig,按回车键,找到IPv4地址,右边的就是你电脑的ip地址),也可以用自动获取本机的ip地址的方法;然后就指定一个端口(注意设置的端口不能和电脑里的其它端口相同,还要设置你写的端口允许通过防火墙或者关闭防火墙都可以),然后就声明Socket对象,详细代码如上。
执行效果图
3.服务端的界面代码如下:
<StackPanel>
<Canvas Margin="10,20" Height="30">
<Label Content="IP:" Height="30" Width="30" FontSize="18" HorizontalContentAlignment="Center" ="8"/>
<TextBox x:Name="txtIp" Height="30" Width="150" FontSize="20" HorizontalContentAlignment="Center" ="41" />
<Label Content="Port:" Height="30" Width="50" FontSize="18" HorizontalContentAlignment="Center" ="210"/>
<TextBox x:Name="txtPort" Text="45000" Height="30" Width="150" FontSize="20" HorizontalContentAlignment="Center" ="263" />
<Button x:Name="btnStartServer" Content="开启服务" Height="30" Width="100" ="460"/>
</Canvas>
<TextBox Name="txtLog" Height="300" AcceptsReturn="True" TextWrapping="Wrap"></TextBox>
<Canvas Margin="0,20" Height="30">
<TextBox x:Name="txtMsg" Height="30" Width="450" FontSize="20" HorizontalContentAlignment="Center" ="0" />
<Button x:Name="btnSendMsg" Content="发送消息" Height="30" Width="100" ="470" />
</Canvas>
</StackPanel>
4.后台代码如下:
using System;
using ;
using ;
using ;
using ;
using ;
using ;
namespace WPF_Sever
{
/// <summary>
/// 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
List<Socket> clientScoketLis = new List<Socket>();//存储连接服务器端的客户端的Socket
public MainWindow()
{
InitializeComponent();
+= BtnStartServer_Click;//事件注册
+= BtnSendMsg_Click;
Closing += MainWindow_Closing;
}
/// <summary>
/// 关闭事件
/// </summary>
private void MainWindow_Closing(object sender, e)
{
//改成for循环即可
for (int i = 0; i < ; i++)//向每个客户端说我下线了
{
ClientExit(null, clientScoketLis[i]);
}
}
/// <summary>
/// 开启服务事件
/// </summary>
private void BtnStartServer_Click(object sender, RoutedEventArgs e)
{
//1、创建Socket对象
//参数:寻址方式,当前为Ivp4 指定套接字类型 指定传输协议Tcp;
Socket socket = new Socket(, , );
//2、绑定端口、IP
IPEndPoint iPEndPoint = new IPEndPoint((GetCurrentLoginIP()), int.Parse());
(iPEndPoint);
//3、开启侦听 10为队列最多接收的数量
(100);//如果同时来了100个连接请求,只能处理一个,队列中10个在等待连接的客户端,其他的则返回错误消息。
//4、开始接受客户端的连接 ,连接会阻塞主线程,故使用线程池。
(new WaitCallback(AcceptClientConnect), socket);
}
/// <summary>
/// 获取本地的IP地址
/// </summary>
/// <returns></returns>
private string GetCurrentLoginIP()
{
///获取本地的IP地址
string ThisloginIP = string.Empty;
foreach (IPAddress _IPAddress in (()).AddressList)
{
if (_IPAddress.() == "InterNetwork")
{
ThisloginIP = _IPAddress.ToString();
}
}
= ThisloginIP;
return ThisloginIP;
}
/// <summary>
/// 线程池线程执行的接受客户端连接方法
/// </summary>
/// <param name="obj">传入的Socket</param>
private void AcceptClientConnect(object obj)
{
//转换Socket
var serverSocket = obj as Socket;
AppendTxtLogText("服务端开始接收客户端连接!");
//不断接受客户端的连接
while (true)
{
//5、创建一个负责通信的Socket
Socket proxSocket = ();
AppendTxtLogText(string.Format("客户端:{0}连接上了!", ()));
//将连接的Socket存入集合
(proxSocket);
//6、不断接收客户端发送来的消息
(new WaitCallback(ReceiveClientMsg), proxSocket);
}
}
/// <summary>
/// 不断接收客户端信息子线程方法
/// </summary>
/// <param name="obj">参数Socke对象</param>
private void ReceiveClientMsg(object obj)
{
var proxSocket = obj as Socket;
//创建缓存内存,存储接收的信息 ,不能放到while中,这块内存可以循环利用
byte[] data = new byte[1020 * 1024];
while (true)
{
int len;
try
{
//接收消息,返回字节长度
len = (data, 0, , );
}
catch (Exception ex)
{
//7、关闭Socket
//异常退出
try
{
ClientExit(string.Format("客户端:{0}非正常退出", ()), proxSocket);
}
catch (Exception)
{
}
return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束
}
if (len <= 0)//判断接收的字节数
{
//7、关闭Socket
//小于0表示正常退出
try
{
ClientExit(string.Format("客户端:{0}正常退出", ()), proxSocket);
}
catch (Exception)
{
}
return;//让方法结束,终结当前客户端数据的异步线程,方法退出,即线程结束
}
//将消息显示到TxtLog
string msgStr = (data, 0, len);
//拼接字符串
AppendTxtLogText(string.Format("接收到客户端:{0}的消息:{1}", (), msgStr));
}
}
/// <summary>
/// 消息发送事件
/// </summary>
private void BtnSendMsg_Click(object sender, RoutedEventArgs e)
{
foreach (Socket proxSocket in clientScoketLis)
{
if ()//判断客户端是否还在连接
{
byte[] data = (this.);
//6、发送消息
(data, 0, , ); //指定套接字的发送行为
this. = null;
}
}
}
/// <summary>
/// 向文本框中追加信息
/// </summary>
/// <param name="str"></param>
private void AppendTxtLogText(string str)
{
if (!(()))//判断跨线程访问
{
//异步方法
this.(new Action<string>(s =>
{
this. = string.Format("{0}\r\n{1}", s, );
}), str);
}
else
{
this. = string.Format("{0}\r\n{1}", str, );
}
}
/// <summary>
/// 客户端退出调用
/// </summary>
/// <param name="msg"></param>
private void ClientExit(string msg, Socket proxSocket)
{
AppendTxtLogText(msg);
(proxSocket);//移除集合中的连接Socket
try
{
if ()//如果是连接状态
{
();//关闭连接
(100);//100秒超时间
}
}
catch (Exception ex)
{
}
}
}
}
运行效果