效果
实现思路
使用TcpListener建一个服务器,接收所有客户端发送的消息,然后由服务器再发送到其他客户端
客户端使用TcpClient,发消息给服务器,接收服务器的消息,不和其他客户端直接交互
服务器端
接收客户端
开启一个线程,死循环去接收客户端.接收到之后放到一个集合里,保存起来,以便转发消息用.每个客户端都再开启一个线程,用于接收这个客户端发送的消息.
接收客户端的方法AcceptTcpClient()是阻塞方法,在程序退出释放资源时会引发异常,可以先使用Pending()方法先判断是否有挂起的链接请求,有请求的话再去接收.这样可以避免退出时引发的异常.
这里取每隔1秒接收一次.
///
///接收客户端///
private voidAcceptClient()
{try{while(_isAccept)
{if(_listener.Pending())
{
TcpClient client=_listener.AcceptTcpClient();
IPEndPoint endpoint= client.Client.RemoteEndPoint asIPEndPoint;
_clients.Add(endpoint.ToString(), client);//添加到前端客户端列表
lbx_Clients.Dispatcher.Invoke(() =>{
lbx_Clients.Items.Add(endpoint.ToString());
});//接收消息线程
Thread reciveMessageThread = newThread(ReciveMessage);
reciveMessageThread.Start(client);
}else{
Thread.Sleep(1000);
}
}
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
接收消息并转发
也是死循环接收,使用Read()方法接收.如果远程主机已关闭连接,Read()将立即返回零字节.此时跳出循环,释放资源,结束此线程.
///
///接收消息///
/// TcpClient
private void ReciveMessage(objectobj)
{
TcpClient client= obj asTcpClient;
IPEndPoint endpoint= null;
NetworkStream stream= null;try{
endpoint= client.Client.RemoteEndPoint asIPEndPoint;
stream=client.GetStream();while (true)
{byte[] data = new byte[1024];//如果远程主机已关闭连接,Read将立即返回零字节
int length = stream.Read(data, 0, data.Length);if (length > 0)
{#region if
string msg = Encoding.UTF8.GetString(data, 0, length);//添加到前端消息列表
lbx_Messages.Dispatcher.Invoke(() =>{
lbx_Messages.Items.Add(string.Format("{0}:{1}", endpoint.ToString(), msg));
});//发送到其他客户端
foreach (KeyValuePair kvp in_clients)
{if (kvp.Value !=client)
{string writeMsg = string.Format("{0}:{1}", endpoint.ToString(), msg);byte[] writeData =Encoding.UTF8.GetBytes(writeMsg);
NetworkStream writeStream=kvp.Value.GetStream();
writeStream.Write(writeData,0, writeData.Length);
}
}#endregion}else{//客户端断开连接 跳出循环
break;
}
}
}catch(Exception ex)
{//Read是阻塞方法 客户端退出是会引发异常 释放资源 结束此线程
}finally{//从前端客户端列表移除
lbx_Clients.Dispatcher.Invoke(() =>{
lbx_Clients.Items.Remove(endpoint.ToString());
});//释放资源
stream.Dispose();
_clients.Remove(endpoint.ToString());
client.Dispose();
}
}
客户端
接收消息
开启线程,死循环接收服务器发送的消息.如果Read()返回0,说明服务器已关闭.
///
///接收消息///
private voidReciveMessage()
{try{
NetworkStream stream=_client.GetStream();while (true)
{byte[] data = new byte[1024];int length = stream.Read(data, 0, data.Length);if (length > 0)
{string msg = Encoding.UTF8.GetString(data, 0, length);//添加到前端消息列表
lbx_Messages.Dispatcher.Invoke(() =>{
lbx_Messages.Items.Add(msg);
});
}else{
MessageBox.Show("服务器已关闭");
stream.Dispose();break;
}
}
}catch(Exception ex)
{//Read是阻塞方法 程序退出释放资源是会引发异常 不做处理 线程结束
}
}
源码下载: