C#网络聊天室
简述
使用VS控制台应用,开发C#网络通信代码。模拟聊天室。
代码
首先创建一个ServerController的解决方案,使用一下脚本:服务器端脚本,ServerTest
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ServerControler
{
public class ServerTest
{
List<Socket> clientList;//客户端集合
Socket socket;
string ip = "127.0.0.1";
int port = 12345;
/// <summary>
/// 构造函数
/// </summary>
public ServerTest()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientList = new List<Socket>();//在构造函数中初始化客户端的集合
}
public void StartServer()
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port);//把IP和端口组合成IPEndPoint的结构
socket.Bind(endPoint);//绑定IP和端口
socket.Listen(10);//设置监听
Thread therd = new Thread(Accept);//开启新线程
therd.IsBackground = true;
therd.Start();
Console.WriteLine("服务器启动成功");
}
/// <summary>
/// 接收客户端的方法,会挂起当前线程
/// </summary>
void Accept()
{
Socket client = socket.Accept();//设置连接
IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
Console.WriteLine(point.Address + "[" + point.Port + "]连接成功");
clientList.Add(client);//连接进来一个客户端就添加到集合里,然后在下面遍历哪个客户端发的消息,再把消息分别发到其他客户端
//会挂起当前线程,所以新开一个线程
Thread thread = new Thread(Receive);
thread.IsBackground = true;
thread.Start(client);
Accept();//尾递归
}
/// <summary>
/// 服务器接收客户端的消息
/// </summary>
/// <param name="obj">线程的参数类型只能是Object类型</param>
void Receive(object obj)//线程的参数类型只能是Object类型
{
Socket client = obj as Socket;//把Object强制转换成Socket
IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
try
{
byte[] msg = new byte[1024];
int msgLenth = client.Receive(msg);
string clientMsg = point.Address + "[" + point.Port + "] 说: " + Encoding.UTF8.GetString(msg, 0, msgLenth);//获得哪个客户端发过来的消息,进行输出
Console.WriteLine(clientMsg);
GuangBo(client, clientMsg);//调用广播这个方法,分发给其他客户端,有人说话了
//client.Send(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(msg, 0, msgLenth)+" (这是服务器返回的消息)"));//服务器往客户端发送消息
Receive(client);//尾递归进行等待下一个消息
}
catch
{
Console.WriteLine(point.Address + "[" + point.Port + "] : " + "断开连接");
clientList.Remove(client);//如果某个客户端退出链接,就从集合里移除
}
}
/// <summary>
/// 遍历哪个客户端发的消息,然后把消息向其他客户端广播出去,形成聊天室
/// </summary>
/// <param name="client">发消息进来的客户端</param>
/// <param name="msg">某个客户端发过来的消息</param>
private void GuangBo(Socket clientOther, string msg)
{
foreach (var client in clientList)
{
if (client == clientOther)
{
//消息是由这个客户端发过来的,不需要有任何响应
}
else
{
client.Send(Encoding.UTF8.GetBytes(msg));//执行Send方法,把消息分发给其他客户端
}
}
}
}
}
服务器端主函数脚本,Program
using System;
namespace ServerControler
{
class Program
{
static void Main(string[] args)
{
ServerTest server = new ServerTest();
server.StartServer();//执行StartServer方法,开启服务器
Console.ReadKey();
}
}
}
再创建一个ClientController的解决方案,使用一下脚本:
客户端脚本,Client
using System;
using System.Collections.Generic;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading;
namespace ClientController
{
public class Client
{
private Socket ClientSocket;
public Client()
{
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Connect(string ip, int port)
{
ClientSocket.Connect(ip, port);
Console.WriteLine("连接上服务器");
Thread thread = new Thread(Receive);
thread.IsBackground = true;
thread.Start();
}
void Receive()
{
while (true)
{
try
{
byte[] msg = new byte[1024];
int msgLenth = ClientSocket.Receive(msg);//ClientSocket.Receive接收消息,返回接受到得长度
Console.WriteLine(Encoding.UTF8.GetString(msg, 0, msgLenth));
}
catch
{
Console.WriteLine("服务器拒绝连接,请重新尝试");
break;
}
}
}
public void Send()
{
Thread thread = new Thread(ReadAndSend);
//thread.IsBackground = true;//此处教程视频里注掉了,说是因为在主函数里写了Console.ReadKey(),主线程会把这个线程给关掉,注掉之后就不会影响这个线程,个人测试下来,不发布还是没问题的,但是发布这个程序之后,会发送不了消息,直接退出,所以还是注掉
thread.Start();//开启线程
}
void ReadAndSend()
{
Console.WriteLine("请输入要发送的内容,不输入直接按下Enter则退出");
string msg = Console.ReadLine();//获取输入的内容
while (msg != "")
{
ClientSocket.Send(Encoding.UTF8.GetBytes(msg));//向服务器发送消息
msg = Console.ReadLine();
}
}
}
}
客户端端主函数脚本,Program
using System;
namespace ClientController
{
class Program
{
static void Main(string[] args)
{
Client client = new Client();
client.Connect("127.0.0.1", 12345);
client.Send();//执行Send方法,启动线程发送消息
Console.ReadKey();
}
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!