基于socket实现的简单的聊天程序

时间:2022-04-11 01:25:56

  记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上。 一个偶然的机会,第二次使用socket做点事情。先看聊天服务器端的实现:

服务器端要实现以下功能:

     1、启动服务,开启监听

     2、持续不断地接收消息

     3、发送消息

启动服务,创建监听socket,绑定Ip和端口:

         /// <summary>
/// 启动服务
/// </summary>
private void Start()
{
socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress address = IPAddress.Parse("10.0.0.31"); IPEndPoint point = new IPEndPoint(address, ); socketwatch.Bind(point); //将套接字的监听队列长度限制为20
socketwatch.Listen(); //创建一个监听线程
threadwatch = new Thread(watchconnecting); threadwatch.IsBackground = true; threadwatch.Start();
}

创建接收数据的Socket:

  //监听客户端发来的请求
private void watchconnecting()
{
Socket connection = null;
while (true) //持续不断监听客户端发来的请求
{
try
{
connection = socketwatch.Accept();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); //提示套接字监听异常
break;
}
//获取客户端的IP和端口号
IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port; //让客户显示"连接成功的"的信息
string sendmsg = "连接服务端成功!\r\n" + "本地IP:" + clientIP + ",本地端口" + clientPort.ToString();
byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);
connection.Send(arrSendMsg); RemoteEndPoint = connection.RemoteEndPoint.ToString(); //客户端网络结点号
dic.Add(RemoteEndPoint, connection); //添加客户端信息 IPEndPoint netpoint = connection.RemoteEndPoint as IPEndPoint; //创建一个通信线程
ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
Thread thread = new Thread(pts);
thread.IsBackground = true;//设置为后台线程,随着主线程退出而退出
//启动线程
thread.Start(connection);
}
}

socketwatch.Accept()
会创建一个新的socket,它用来负责和某个客户端的通讯。 接收数据:
         private void recv(object socketclientpara)
{ Socket socketServer = socketclientpara as Socket;
while (true)
{
byte[] arrServerRecMsg = new byte[ * ];
try
{
int length = socketServer.Receive(arrServerRecMsg); string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, , length); this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strSRecMsg, IdentityName = socketServer.RemoteEndPoint.ToString() });
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
socketServer.Close();
break;
}
}
}

把从客户端接收过来的字节流变为字符串,然后添加到页面上。

发送消息:

         private static object lockPool = new object();
public static ObservableCollection<Message> MessagePool = new ObservableCollection<Message>();
private void send_Click(object sender, RoutedEventArgs e)
{
string msg = this.message.Text; this.message.Clear(); lock (lockPool)
{
MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = msg, IdentityName = "wbq" });
} string sendMsg = msg;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg); if (dic.Count > )
dic.First().Value.Send(bytes);
}
dic.First().Value.Send,从字典中获取到之前创建好的通讯socket,然后调用send方法。

客户端需要实现以下功能:
1、和服务器建立连接
2、接收数据
3、发送数据 建立连接:
    private void Start()
{ //定义一个套接字监听
socketclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var servers= GetServers(); if (servers.Count > )
{ //获取文本框中的IP地址
IPAddress address = IPAddress.Parse(servers.First().IPToPing); //将获取的IP地址和端口号绑定在网络节点上
IPEndPoint point = new IPEndPoint(address, int.Parse(servers.First().Port)); try
{
//客户端套接字连接到网络节点上,用的是Connect
socketclient.Connect(point);
}
catch (Exception)
{
//MessageBox.
MessageBox.Show("连接失败\r\n");
return;
} threadclient = new Thread(recv); threadclient.IsBackground = true; threadclient.Start();
}
}

接收消息:

        // 接收服务端发来信息的方法
private void recv()//
{
while (true)//持续监听服务端发来的消息
{
try
{
//定义一个1M的内存缓冲区,用于临时性存储接收到的消息
byte[] arrRecvmsg = new byte[ * ]; //将客户端套接字接收到的数据存入内存缓冲区,并获取长度
int length = socketclient.Receive(arrRecvmsg); //将套接字获取到的字符数组转换为人可以看懂的字符串
string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, , length); this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strRevMsg, IdentityName = socketclient.RemoteEndPoint.ToString() });
});
}
catch (Exception ex)
{
MessageBox.Show("远程服务器已经中断连接" + ex.Message);
break;
}
}
}
发送消息:
         private void send_Click(object sender, RoutedEventArgs e)
{
string strRevMsg = this.message.Text;
this.message.Clear(); lock (lockPool)
{
MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strRevMsg, IdentityName = "我(" + socketclient.LocalEndPoint.ToString() + ")" });
} //将输入的内容字符串转换为机器可以识别的字节数组
byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(strRevMsg);
//调用客户端套接字发送字节数组
socketclient.Send(arrClientSendMsg);
}
经过和同事的测试,可以实现简单的文字聊天,此代码仅为测试代码,若要用于实际的项目中,需要很大改进,比如socket异步建立,消息接收和发送等等。