c#基于WinForm的Socket实现简单的聊天室 IM

作者:天天向上518 时间:2021-11-27 04:47:57 

1:什么是Socket

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。

从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。

2:客服端和服务端的通信简单流程

c#基于WinForm的Socket实现简单的聊天室 IM

3:服务端Code:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChartService
{
   using System.Net;
   using System.Net.Sockets;
   using System.Threading;
   using ChatCommoms;
   using ChatModels;

public partial class ServiceForm : Form
   {
       Socket _socket;
       private static List<ChatUserInfo> userinfo = new List<ChatUserInfo>();
       public ServiceForm()
       {
           InitializeComponent();

}

private void btnServicStart_Click(object sender, EventArgs e)
       {
           try
           {
               string ip = textBox_ip.Text.Trim();
               string port = textBox_port.Text.Trim();
               if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(port))
               {
                   MessageBox.Show("IP与端口不可以为空!");
               }
               ServiceStartAccept(ip, int.Parse(port));
           }
           catch (Exception)
           {
               MessageBox.Show("连接失败!或者ip,端口参数异常");
           }
       }
       public void ServiceStartAccept(string ip, int port)
       {
           Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
           IPEndPoint endport = new IPEndPoint(IPAddress.Parse(ip), port);
           socket.Bind(endport);
           socket.Listen(10);
           Thread thread = new Thread(Recevice);
           thread.IsBackground = true;
           thread.Start(socket);
           textboMsg.AppendText("服务开启ok...");
       }

/// <summary>
       /// 开启接听服务
       /// </summary>
       /// <param name="obj"></param>
       private void Recevice(object obj)
       {
           var socket = obj as Socket;
           while (true)
           {
               string remoteEpInfo = string.Empty;
               try
               {
                   Socket txSocket = socket.Accept();
                   _socket = txSocket;
                   if (txSocket.Connected)
                   {
                       remoteEpInfo = txSocket.RemoteEndPoint.ToString();
                       textboMsg.AppendText($"\r\n{remoteEpInfo}:连接上线了...");
                       var clientUser = new ChatUserInfo
                       {
                           UserID = Guid.NewGuid().ToString(),
                           ChatUid = remoteEpInfo,
                           ChatSocket = txSocket
                       };
                       userinfo.Add(clientUser);

listBoxCoustomerList.Items.Add(new ChatUserInfoBase { UserID = clientUser.UserID, ChatUid = clientUser.ChatUid });
                       listBoxCoustomerList.DisplayMember = "ChatUid";
                       listBoxCoustomerList.ValueMember = "UserID";

ReceseMsgGoing(txSocket, remoteEpInfo);
                   }
                   else
                   {
                       if (userinfo.Count > 0)
                       {
                           userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault());
                           //移除下拉框对于的socket或者叫用户
                       }
                       break;
                   }
               }
               catch (Exception)
               {
                   if (userinfo.Count > 0)
                   {
                       userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault());
                       //移除下拉框对于的socket或者叫用户
                   }
               }
           }

}

/// <summary>
       /// 接受来自客服端发来的消息
       /// </summary>
       /// <param name="txSocket"></param>
       /// <param name="remoteEpInfo"></param>
       private void ReceseMsgGoing(Socket txSocket, string remoteEpInfo)
       {

//退到一个客服端的时候 int getlength = txSocket.Receive(recesiveByte); 有抛异常
           Thread thread = new Thread(() =>
           {
               while (true)
               {
                   try
                   {
                       byte[] recesiveByte = new byte[1024 * 1024 * 4];
                       int getlength = txSocket.Receive(recesiveByte);
                       if (getlength <= 0) { break; }

var getType = recesiveByte[0].ToString();
                       string getmsg = Encoding.UTF8.GetString(recesiveByte, 1, getlength - 1);
                       ShowMsg(remoteEpInfo, getType, getmsg);
                   }
                   catch (Exception)
                   {
                       //string userid = userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo)?.ChatUid;
                       listBoxCoustomerList.Items.Remove(remoteEpInfo);
                       userinfo.Remove(userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo));//从集合中移除断开的socket

listBoxCoustomerList.DataSource = userinfo;//重新绑定下来的信息
                       listBoxCoustomerList.DisplayMember = "ChatUid";
                       listBoxCoustomerList.ValueMember = "UserID";
                       txSocket.Dispose();
                       txSocket.Close();
                   }
               }
           });
           thread.IsBackground = true;
           thread.Start();

}

private void ShowMsg(string remoteEpInfo, string getType, string getmsg)
       {
           textboMsg.AppendText($"\r\n{remoteEpInfo}:消息类型:{getType}:{getmsg}");
       }
       private void Form1_Load(object sender, EventArgs e)
       {
           CheckForIllegalCrossThreadCalls = false;
           this.textBox_ip.Text = "192.168.1.101";//初始值
           this.textBox_port.Text = "50000";
       }

/// <summary>
       /// 服务器发送消息,可以先选择要发送的一个用户
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void btnSendMsg_Click(object sender, EventArgs e)
       {
           var getmSg = textBoxSendMsg.Text.Trim();
           if (string.IsNullOrWhiteSpace(getmSg))
           {
               MessageBox.Show("要发送的消息不可以为空", "注意"); return;
           }
           var obj = listBoxCoustomerList.SelectedItem;
           int getindex = listBoxCoustomerList.SelectedIndex;
           if (obj == null || getindex == -1)
           {
               MessageBox.Show("请先选择左侧用户的用户"); return;
           }
           var getChoseUser = obj as ChatUserInfoBase;
           var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum);
           userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket?.Send(sendMsg);
       }

/// <summary>
       /// 给所有登录的用户发送消息,群发了
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void button1_Click(object sender, EventArgs e)
       {
           var getmSg = textBoxSendMsg.Text.Trim();
           if (string.IsNullOrWhiteSpace(getmSg))
           {
               MessageBox.Show("要发送的消息不可以为空", "注意"); return;
           }
           if (userinfo.Count <= 0)
           {
               MessageBox.Show("暂时没有客服端登录!"); return;
           }
           var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum);
           foreach (var usersocket in userinfo)
           {
               usersocket.ChatSocket?.Send(sendMsg);
           }
       }

/// <summary>
       /// 服务器给发送震动
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void btnSendSnak_Click(object sender, EventArgs e)
       {
           var obj = listBoxCoustomerList.SelectedItem;
           int getindex = listBoxCoustomerList.SelectedIndex;
           if (obj == null || getindex == -1)
           {
               MessageBox.Show("请先选择左侧用户的用户"); return;
           }
           var getChoseUser = obj as ChatUserInfoBase;

byte[] sendMsgByte = ServiceSockertHelper.GetSendMsgByte("", ChatTypeInfoEnum.Snake);
           userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket.Send(sendMsgByte);
       }

}
}

4:客服端Code:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatClient
{
   using ChatCommoms;
   using System.Net;
   using System.Net.Sockets;
   using System.Threading;

public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

private void Form1_Load(object sender, EventArgs e)
       {
           CheckForIllegalCrossThreadCalls = false;
           this.textBoxIp.Text = "192.168.1.101";//先初始化一个默认的ip等
           this.textBoxPort.Text = "50000";
       }

Socket clientSocket;
       /// <summary>
       /// 客服端连接到服务器
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void btnServicStart_Click(object sender, EventArgs e)
       {
           try
           {
               var ipstr = textBoxIp.Text.Trim();
               var portstr = textBoxPort.Text.Trim();
               if (string.IsNullOrWhiteSpace(ipstr) || string.IsNullOrWhiteSpace(portstr))
               {
                   MessageBox.Show("要连接的服务器ip和端口都不可以为空!");
                   return;
               }
               clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
               clientSocket.Connect(IPAddress.Parse(ipstr), int.Parse(portstr));
               labelStatus.Text = "连接到服务器成功...!";
               ReseviceMsg(clientSocket);

}
           catch (Exception)
           {
               MessageBox.Show("请检查要连接的服务器的参数");
           }
       }
       private void ReseviceMsg(Socket clientSocket)
       {

Thread thread = new Thread(() =>
            {
                while (true)
                {
                    try
                    {
                        Byte[] byteContainer = new Byte[1024 * 1024 * 4];
                        int getlength = clientSocket.Receive(byteContainer);
                        if (getlength <= 0)
                        {
                            break;
                        }
                        var getType = byteContainer[0].ToString();
                        string getmsg = Encoding.UTF8.GetString(byteContainer, 1, getlength - 1);

GetMsgFomServer(getType, getmsg);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            });
           thread.IsBackground = true;
           thread.Start();

}

private void GetMsgFomServer(string strType, string msg)
       {
           this.textboMsg.AppendText($"\r\n类型:{strType};{msg}");
       }

/// <summary>
       /// 文字消息的发送
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       private void btnSendMsg_Click(object sender, EventArgs e)
       {
           var msg = textBoxSendMsg.Text.Trim();
           var sendMsg = ServiceSockertHelper.GetSendMsgByte(msg, ChatModels.ChatTypeInfoEnum.StringEnum);
           int sendMsgLength = clientSocket.Send(sendMsg);
       }
   }
}

5:测试效果:

c#基于WinForm的Socket实现简单的聊天室 IM

6:完整Code GitHUb下载路径 

https://github.com/zrf518/WinformSocketChat.git

7:这个只是一个简单的聊天练习Demo,待进一步完善(实现部分功能,传递的消息byte[0]为消息的类型,用来判断是文字,还是图片等等),欢迎大家指教

来源:https://www.cnblogs.com/Fengge518/p/14536940.html

标签:c#,WinForm,聊天室,socket,IM
0
投稿

猜你喜欢

  • Java实现抠图片文字或签名的完整代码

    2023-04-18 00:04:44
  • java生成xml格式文件的方法

    2023-11-23 02:40:32
  • c#文件名/路径处理方法示例

    2021-11-28 21:02:40
  • Java程序员新手老手常用的八大开发工具

    2021-12-04 03:39:04
  • Idea中maven项目实现登录验证码功能

    2023-11-29 16:50:51
  • Java8 HashMap键与Comparable接口小结

    2023-11-29 10:10:31
  • Unity实现3D循环滚动效果

    2023-04-22 14:05:47
  • 浅析12306售票算法(java版)

    2023-11-16 10:27:12
  • C#编程之事务用法

    2023-08-20 05:50:37
  • MyBatis图文并茂讲解注解开发一对一查询

    2023-12-07 11:01:18
  • 五分钟手撸一个Spring容器(萌芽版)

    2021-07-29 02:41:54
  • Springboot Mybatis Plus自动生成工具类详解代码

    2022-09-17 12:01:57
  • java网络编程基础知识介绍

    2023-01-10 20:37:44
  • Dubbo实现分布式日志链路追踪

    2023-08-23 21:00:54
  • spring-boot-maven-plugin报红解决方案(亲测有效)

    2022-07-23 01:16:46
  • 使用Spring Cloud Feign远程调用的方法示例

    2021-12-06 10:30:09
  • springboot大文件上传、分片上传、断点续传、秒传的实现

    2023-06-16 02:18:30
  • Java 1.8使用数组实现循环队列

    2022-02-11 04:00:10
  • Java中ArrayList集合的常用方法大全

    2023-09-01 15:23:30
  • Spring Boot 配置和使用多线程池的实现

    2022-09-04 19:53:02
  • asp之家 软件编程 m.aspxhome.com