1. 服务器端流程如下:
创建一个"监听"Socket,绑定监听端口,设置监听队列,循环等待客户端连接,通过Accept()这个方法回去监听客户端连接,一旦连接成功,将会返回一个”通信”Socket。
private void BtnListen_Click(object sender, EventArgs e)
{
//当点击开始监听时,在服务器创建一个负责监听IP地址跟端口号的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//提供一个 IP 地址,指示服务器必须侦听所有网络接口上的客户端活动。 此字段为只读。
IPAddress ip = IPAddress.Any;//此时用Any()这个方法得到的ip地址是 0.0.0.0而它表示的是【本机所有ip地址】
// ip = IPAddress.Parse(txtIp.Text);//若换成它,那客户端只能连接txtIp文本下的ip地址。
//创建连接点对象--IPEndPoint类包含应用程序连接到主机上的服务所需的主机和本地或远程端口信息。 通过将主机的 IP 地址和服务端口号组合在一起,类 IPEndPoint 会形成到服务的连接点。
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//绑定监听端口
socketWatch.Bind(point);
showMsg("监听成功");
//设置监听队列
socketWatch.Listen(10);
//开启一个 新的线程 循环等待客户端的连接
Thread th = new Thread(Listen);
th.IsBackground= true;
th.Start(socketWatch);
}
2. 客户端流程如下:
创建一个“通信”Socket,一旦调用Connect()方法,Accept()立刻能够监听到,然后对ip和端口号进行比对,比对成功,就建立了连接。
//创建一个负责通信的Socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//每一次重新连接都会实例化一个新的Socket
IPAddress ip = IPAddress.Parse(txtServer.Text);//将 IP 地址字符串转换为 IPAddress 实例。根据txtServer文本框中的文本转换成ip地址
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(txtPort.Text));//连接点对象:包含ip地址 和 端口号
try
{
socketSend.Connect(point);//开始建立连接---标记:这里可能会出现异常
}
catch (SocketException)
{
txtLog.Text = "客户端ip地址可能与服务端ip地址不匹配,请检查ip地址后再连接";
Console.WriteLine("客户端ip地址可能与服务端ip地址不匹配,请检查ip地址后再连接");//解决客户端ip地址与服务端ip地址不匹配
return;
}
ShowMsg("连接成功");
3. 客户端给服务端发送消息,调用Send()方法。
string str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);//将指定字符串中的所有字符按照指定编码格式,编码成字节序列
socketSend.Send(buffer);
4.服务端接收客户端发过来的消息,调用Recive()方法
//-----开启 一个新线程不停接收客户端发过来的消息
Thread th = new Thread(Recive);
th.IsBackground= true;
th.Start(socketSend);
private void Recive(object o)
{
socketSend = o as Socket;
while (true)
{
//客户端连接成功后,服务器应该循环接收客户端发过来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
try
{
int r = socketSend.Receive(buffer);//将从客户端发过来的数据,存到buffer缓冲流中,并返回实际受到的字节数。
if (r == 0)
{
showMsg(socketSend.RemoteEndPoint + ":" + "下线了");
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);
showMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch (SocketException)
{
Console.WriteLine(socketSend.RemoteEndPoint + ":" + "下线了");
showMsg(socketSend.RemoteEndPoint.ToString() + ":" + "下线了");//-----貌似有点问题
socketSend.Close();//关闭 套接字资源
break;
}
}
}
5.服务端给客户端发消息,调用Send()方法
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
6.客户端接收服务端发送过来的消息,调用Recive()方法
//开启一个线程接收服务端发过来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start();
private void Recive()
{
while (true)
{
byte[] buffer = new byte[1024];
try
{
int r = socketSend.Receive(buffer);//陷入等待状态 将服务器中Socket中发送的数据接收,缓冲到buffer中,并返回实际接收的字节数
if (r == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch (Exception)
{
/* ShowMsg(socketSend.RemoteEndPoint + ":" + "下线了");//待修正----
socketSend.Close();
break;*/
}
}
}
7. 功能实现效果图
7.1 客户端成功连接服务端
7.2客户端发送消息,服务端响应效果图
7.3 客户端下线通知效果
8. 未解决的难题
当服务器出现“宕机” ,客户端是连接不上的,并且要给出相应提示,但是我这里逻辑没有处理好导致一直抛异常。