使用Winfrom写一个聊天软件
- 效果图
- 原理
- 代码实现
- 服务端
- 客户端
- 注意事项
效果图
原理
代码实现
服务端
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScoketServerTest
{
public partial class Server : Form
{
public Server()
{
InitializeComponent();
}
/// <summary>
/// socket套接字
/// </summary>
Socket socketServer = null;
/// <summary>
/// 客户端
/// </summary>
Socket socketClienCon = null;
/// <summary>
/// 客户端信息
/// </summary>
string clientIpMsg = string.Empty;
/// <summary>
/// 服务器是否关闭 false:开启 true:已关闭
/// </summary>
bool isClose = false;
private void Server_Load(object sender, EventArgs e)
{
// 获取当前主机名
this.textBox1.Text = System.Net.Dns.GetHostName();
// 默认端口设置为33333
this.portTex.Text = "33333";
// 根据主机名获取ip地址
//注意获取的是IPV4的地址,有些电脑如果第一个就是IPV4可以把索引'1'更换成'0'
this.ipTex.Text = System.Net.Dns.GetHostEntry(this.textBox1.Text).AddressList[1].ToString();
}
private void btnOpen_Click(object sender, EventArgs e)
{
try
{
// 获取输入框的ip地址
IPAddress ip = IPAddress.Parse(this.ipTex.Text.ToString().Trim());
// 获取端口号
int port = int.Parse(this.portTex.Text.ToString().Trim());
IPEndPoint ipe = new IPEndPoint(ip,port);
socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 绑定网络终结点
socketServer.Bind(ipe);
// 设置监听最大连接数
socketServer.Listen(10);
isClose = false;
this.lstRev.Items.Add(string.Format("服务器已开启,开始监听消息"));
this.lstRev.Items.Add(string.Format("当前主机名:{0}", this.textBox1.Text));
this.lstRev.Items.Add(string.Format("当前IP:{0}", System.Net.Dns.GetHostEntry(this.textBox1.Text).AddressList[0].ToString()));
Thread clientThread = new Thread(ListenTh); //创建一个线程,用于监听客户端连接
clientThread.IsBackground = true; //设置为后台线程
clientThread.Start(); //开启线程
Thread revThread = new Thread(RevTh); //创建一个线程,用于监听客户端发来的消息
revThread.IsBackground = true;//设置为后台线程
revThread.Start(); //开启线程
}
catch (Exception ex)
{
string errorMsg = string.Format("服务器开启失败,失败原因:{0}", ex.Message.ToString());
this.lstRev.Items.Add(errorMsg);
}
}
/// <summary>
/// 监听客户端
/// </summary>
private void ListenTh()
{
while (!isClose)
{
try
{
socketClienCon = socketServer.Accept(); //为监听到的客户端创建新的套接字
IPAddress clientIp = (socketClienCon.RemoteEndPoint as IPEndPoint).Address; //获取连接的客户端的IP地址
int clientPort = (socketClienCon.RemoteEndPoint as IPEndPoint).Port; //获取连接的客户端的端口号
clientIpMsg = string.Format("客户端IP:{0},端口号:{1}", clientIp, clientPort);
OnlineClient(clientIpMsg); //在线用户并打印到在线用户窗口
}
catch (Exception ex)
{
string error = string.Format("监听客户端信息异常,错误原因:{0}", ex.Message.ToString());
Recevice(error);
break;
}
}
}
delegate void OnlineClientDele(string clientMsg); //创建在线用户委托方法
/// <summary>
/// 在线用户
/// </summary>
/// <param name="clientMsg">在线用户信息</param>
private void OnlineClient(string clientMsg)
{
if (this.InvokeRequired)
{
OnlineClientDele oel = new OnlineClientDele(OnlineClient);
this.Invoke(oel, new object[] { clientMsg });
}
else
{
this.lstClient.TopIndex = this.lstClient.Items.Count - 1;
this.lstClient.Items.Add(clientMsg);
}
}
/// <summary>
/// 接收客户端消息
/// </summary>
private void RevTh()
{
while (!isClose)
{
if (socketClienCon != null)
{
try
{
byte[] clientMsg = new byte[1024]; //创建接收消息缓存数组
int msgLen = socketClienCon.Receive(clientMsg); //接收从客户端发来的数据
if (msgLen == 0)
{
break;
}
else
{
string msg = string.Format("{0}【收到 ← 来自:{1}】:\n{2}", DateTime.Now, clientIpMsg, Encoding.UTF8.GetString(clientMsg, 0, msgLen));
Recevice(msg); //接收消息并打印到对话窗口
}
}
catch (Exception ex)
{
string error = string.Format("接收客户端消息异常,错误原因:{0}", ex.Message.ToString());
Recevice(error);
break;
}
}
}
}
delegate void ReceviceDele(string msgStr); //创建接收消息委托方法
/// <summary>
/// 接收消息
/// </summary>
/// <param name="msg">客户端发来的消息</param>
private void Recevice(string msg)
{
if (this.InvokeRequired)
{
ReceviceDele rel = new ReceviceDele(Recevice);
this.Invoke(rel, new object[] { msg });
}
else
{
this.lstRev.TopIndex = this.lstRev.Items.Count - 1;
this.lstRev.Items.Add(msg);
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
string msg = this.txtSend.Text.ToString().Trim();
byte[] msgByt = Encoding.UTF8.GetBytes(msg);
socketClienCon.Send(msgByt);
this.lstRev.Items.Add(string.Format("{0}【发送 → 至 {1}】:\n{2}", DateTime.Now, clientIpMsg, msg));
this.txtSend.Text = "";
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
isClose = true;
socketServer.Close();
}
private void btnClose_Click(object sender, EventArgs e)
{
isClose = true;
socketServer.Close();
}
}
}
客户端
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebspcketClientTest
{
public partial class Client : Form
{
public Client()
{
InitializeComponent();
}
/// <summary>
/// socket套接字
/// </summary>
Socket cilentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
bool isClose = true;
private void Client_Load(object sender, EventArgs e)
{
this.portTex.Text = "33333";
}
private void btnOpen_Click(object sender, EventArgs e)
{
//获取ip
IPAddress ip = null;
if (!string.IsNullOrEmpty(this.ipTex.Text.ToString().Trim()))
{
ip = IPAddress.Parse(this.ipTex.Text.ToString().Trim());
}
else if(!string.IsNullOrEmpty(this.texHostName.Text.ToString().Trim()))
{
IPAddress[] addressList = Dns.GetHostEntry(this.texHostName.Text.ToString().Trim()).AddressList;
// 根据HostName 获取IPV4地址
string ipStr = addressList[0].ToString();
if (ipStr.Length > 17)
{
ipStr = addressList[1].ToString();
}
// IP地址
ip = IPAddress.Parse(ipStr);
this.ipTex.Text = ip.ToString();
}
else
{
MessageBox.Show("无法获取主机地址!");
this.richTextBox1.Text += "无法获取主机地址!\n";
return;
}
//获取端口号
IPEndPoint ep = new IPEndPoint(ip, int.Parse(this.portTex.Text));
//ws = new WebSocketSharp.WebSocket("ws://" + this.texHostName.Text + ":" + this.portTex.Text);
try
{
//ws.Connect();
//建立连接
cilentSocket.Connect(ep);
this.richTextBox1.Text += "连接成功!\n";
isClose = false;
Thread th = new Thread(StartMsg);
th.IsBackground = true;
th.Start();
}
catch (Exception ex)
{
this.richTextBox1.Text += string.Format("连接失败,原因{0}1\n", ex.ToString());
}
}
// 监听服务器信息
public void StartMsg()
{
while (!isClose)
{
try
{
//发送消息的大小
var bytes = new byte[1024 * 1024];
var mlength = cilentSocket.Receive(bytes);
//将字节转换为字符串
string msg = Encoding.UTF8.GetString(bytes, 0, mlength);
this.Invoke(new Action(() =>
{
this.richTextBox1.Text += string.Format("【收到 ← 来自:{0}】:\n{1}\n", DateTime.Now, msg);
}));
}
catch (Exception ex)
{
this.Invoke(new Action(() =>
{
this.richTextBox1.Text += string.Format("连接异常{0}\n", ex.ToString());
isClose = true;
}));
}
}
}
private void btnSend_Click(object sender, EventArgs e)
{
//把要发送的字符串转化为字节
var bytes = Encoding.UTF8.GetBytes(this.txtSend.Text.Trim());
cilentSocket.Send(bytes);
this.richTextBox1.Text += string.Format("{0}【发送 → 至 {1}】:\n{2}\n", DateTime.Now,this.ipTex.Text, this.txtSend.Text.ToString().Trim());
this.txtSend.Text = "";
}
private void button1_Click(object sender, EventArgs e)
{
isClose = true;
}
}
}
注意事项
- 代码是直接可以直接使用的,但是注意这是两个项目的代码,所以需要创建两个项目,一个客户端一个服务端;
- 需要为按钮绑定点击事件才可以使事件生效;
- 设置ip地址的时候要符合自己网段的ip,否则无法开启服务器,另外也可以使用
.127.0.0.1
- 在本项目中客户端与服务端发送消息使用的是字节发送,注意发出的编码与接收的编码要一致,否则无法识别.