一、画页面
1. Server端窗口
2. Client端窗口
二、服务端启动服务监听
1.导入命名空间
using System.Net.Sockets;
using System.Net;
using System.Threading;
2.监听事件
(1)
private void btnStartServer_Click(object sender, EventArgs e)
{
//1.1实例化listenSocket
listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//1.2为listenSocket套接字 标识绑定 IP和端口
IPAddress address = IPAddress.Parse(tbIp.Text.Trim());
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(tbPort.Text.Trim()));
listenSocket.Bind(endPoint);
listenSocket.Listen(10);
//1.3派出一个监听线程去监听请求事件
listenThread = new Thread(ListenStart);
listenThread.IsBackground = true;
listenThread.Start();
}
(2)监听方法ListenStart()
Socket communicationSocket;
int userId = 1;
void ListenStart()
{
showMsg("监听服务已启动!");
//2.1 listenSocket 套接字监听并生成一个通信套接字 communicationSocket
communicationSocket = listenSocket.Accept();
listUser.Items.Add(userId +" - " +communicationSocket.RemoteEndPoint.ToString());
showMsg("有客户端连接!");
Thread communicationThread = new Thread(ReciveMsg);
communicationThread.IsBackground = true;
communicationThread.Start();
}
至此已完成以下功能
(3)在构造方法中还需要加入
TextBox.CheckForIllegalCrossThreadCalls = false;
原理:
在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件,如果需要访问窗口中的控件,可以在窗口构造函数中将CheckForIllegalCrossThre
三、客户端连接
1. 生成客户端通信套接字
connSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(tbIp.Text.Trim());
IPEndPoint endPoint = new IPEndPoint(address,int.Parse(tbPort.Text.Trim()));
connSocket.Connect(endPoint);
四、服务端与客户端聊天信息的收发
1. 服务端
(1)派出接受消息的线程
Thread communicationThread = new Thread(ReciveMsg);
communicationThread.IsBackground = true;
communicationThread.Start();
(2)循环调用接受消息的方法
bool isReceiveMSg = true;
void ReciveMsg()
{
try
{
while (isReceiveMSg)
{
byte[] arrMsg = new byte[1024 * 1024];
int length = communicationSocket.Receive(arrMsg);
string strMsg = Encoding.UTF8.GetString(arrMsg, 0, length);
showMsg(strMsg);
}
}
catch (SocketException se)
{
isReceiveMSg = false;
}
catch (Exception ex)
{
isReceiveMSg = false;
}
}
(3)发送消息
private void btnSendMsg_Click(object sender, EventArgs e)
{
byte[] arrMsg = Encoding.UTF8.GetBytes(tbSendMsg.Text.Trim());
communicationSocket.Send(arrMsg);
tbSendMsg.Text = "";
}
2. 客户端
(1)派出接受消息的通信线程
connThread = new Thread(ReceiveMsg);
connThread.IsBackground = true;
connThread.Start();
(2)接受消息的方法
bool isReceiveMsg = true;
void ReceiveMsg()
{
try
{
while (isReceiveMsg)
{
byte [] arrMsg = new byte[1024*1024];
int length = connSocket.Receive(arrMsg);
string strMsg = Encoding.UTF8.GetString(arrMsg,0,length);
showMsg(strMsg);
}
}
catch(SocketException se)
{
isReceiveMsg = false;
}
catch(Exception ex)
{
isReceiveMsg = false;
}
}
(3)发送消息
private void btnSendMsg_Click(object sender, EventArgs e)
{
byte[] arrMsg = Encoding.UTF8.GetBytes(tbSendMsg.Text.Trim());
connSocket.Send(arrMsg);
tbSendMsg.Text = "";
}
至此Server端已经可以与Client端进行通信了
五、优化考虑
考虑到服务端可能会有多个客户端同时聊天的情况,我们将服务端消息通信的过程写成一个通用的消息通信类当中MsgConnection,每次实例化时就把它放入字典集合中