基于c#用Socket做一个局域网聊天工具

作者:Create Chen 时间:2023-08-17 09:36:14 

程序设计成为简单的服务端和客户端之间的通信, 但通过一些方法可以将这两者进行统一起来, 让服务端也成为客户端, 让客户端也成为服务端, 使它们之间可以互相随时不间断的通信. 考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的.

作为服务端, 要声明一个Socket A并绑定(Bind)某一个IP+这个IP指定的通信端口, 比如这个是127.0.0.1:9050, 然后开始监听(Listen), Listen可以监听来自多个IP传过来的连接请求, 具体可以同时连接几个客户端, Listen方法中可以设定一个参数. 如果Listen到某一个客户端发来连接请求了, 这时定义一个新的Socket B专门负责与这个客户端的通信, Socket B = A.Accept(). 这时可以获取这个客户端的IP和端口,  IPEndPoint C = (IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分别表示客户端C的IP地址和端口. 这时通过B.Send()方法就可以给C发送消息了, B.Receive()可以接收客户端C发来的信息.

作为客户端, 也需要声明一个Socket D并绑定某一个IP+本机一个未被占用的端口, 定义IPEndPoint E表示要进行连接的服务端Socket, 要指明E的IP和端口, 这样才可以进行端口对端口之间的通信, 接下来就可以尝试D.Connect(E), 连接成功之后就可以发送和接收数据了, D.Send(), D.Receive.

发送消息时, 数据都是以字节或字节数组为单位进行传输的, 比如我客户端D要发送"Hello World"则要这样写: D.Send(Encoding.ASCII.GetBytes("Hello World")).  接受消息时, 也是以字节或字节数组, 比如服务端要接受D刚才发送的Hello World, 可以这样写: Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); stringdata这时就是Hello World.

上面只是大概的阐述了服务端与客户端之间的通信过程, 在网上找到了具体的代码例子, 也贴过来参考参考. 这个例子没有将服务端与客户端统一起来, 他是分别写服务端和客户端的.

服务端代码


using System;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpserver
{
  ///  <summary>
  /// Class1 的摘要说明。
  ///  </summary>
  class server
 {
    ///  <summary>
    /// 应用程序的主入口点。
    ///  </summary>
   [STAThread]
    static  void Main( string [] args)
   {
      //
      // TODO: 在此处添加代码以启动应用程序
      //
     int recv; // 用于表示客户端发送的信息长度
     byte [] data;// = new  byte [ 1024 ]; // 用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组
     IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050 ); // 本机预使用的IP和端口
     Socket newsock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
     newsock.Bind(ipep); // 绑定
     newsock.Listen( 10 ); // 监听
     Console.WriteLine( " waiting for a client " );
     Socket client = newsock.Accept(); //当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
     IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint;
     Console.WriteLine( " connect with client: " + clientip.Address + " at port: " + clientip.Port);
     string welcome = " welcome here! " ;
     data = Encoding.ASCII.GetBytes(welcome);
     client.Send(data,data.Length,SocketFlags.None); // 发送信息
     while ( true )
     { // 用死循环来不断的从客户端获取信息
       data = new  byte [ 1024 ];
       recv = client.Receive(data);
       Console.WriteLine( " recv= " + recv);
       if (recv == 0 ) // 当信息长度为0,说明客户端连接断开
          break ;
       Console.WriteLine(Encoding.ASCII.GetString(data, 0 ,recv));
       client.Send(data,recv,SocketFlags.None);
     }
     Console.WriteLine( " Disconnected from " + clientip.Address);
     client.Close();
     newsock.Close();
   }
 }
}

客户端代码


using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpclient
{
 ///  <summary>
 /// Class1 的摘要说明。
 ///  </summary>
 class client
 {
   ///  <summary>
   /// 应用程序的主入口点。
   ///  </summary>
   [STAThread]
   static void Main(string[] args)
   {
     //
     // TODO: 在此处添加代码以启动应用程序
     //
     byte[] data = new byte[1024];
     Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     newclient.Bind(new IPEndPoint(IPAddress.Any, 905));
     Console.Write(" please input the server ip: ");
     string ipadd = Console.ReadLine();
     Console.WriteLine();
     Console.Write(" please input the server port: ");
     int port = Convert.ToInt32(Console.ReadLine());
     IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port); // 服务器的IP和端口
     try
     {
       // 因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。
       newclient.Connect(ie);
     }
     catch (SocketException e)
     {
       Console.WriteLine(" unable to connect to server ");
       Console.WriteLine(e.ToString());
       return;
     }
     int receivedDataLength = newclient.Receive(data);
     string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength);
     Console.WriteLine(stringdata);
     while (true)
     {
       string input = Console.ReadLine();
       if (input == " exit ")
         break;
       newclient.Send(Encoding.ASCII.GetBytes(input));
       data = new byte[1024];
       receivedDataLength = newclient.Receive(data);
       stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength);
       Console.WriteLine(stringdata);
     }
     Console.WriteLine(" disconnect from sercer ");
     newclient.Shutdown(SocketShutdown.Both);
     newclient.Close();
   }
 }
}

上面的服务端和客户端都是控制台应用程序, 想办法做一个窗体类型的, 思路就是另起一个线程, 这个线程专门负责两端建立连接. 如果不采用另起线程的方法, 当等待连接而没有连接上, 或者主动连接, 服务端还没有相应时, 程序就会出现没有响应的假死状态.

当这个线程将两个端口连接成功后, 就让程序进入一个死循环, 这个死循环负责不断的接收是否有消息传来, 传来的话就在txtGetMsg中显示出来:


while (true)  // 用死循环来不断的获取信息
{
 data = new byte[1024];
 recv = newclient.Receive(data);

uiContext.Send(new SendOrPostCallback(
 state =>
 {
   int txtGetMsgLength = txtGetMsg.Text.Length;
   string recMsg = "Friend:    " + System.DateTime.Now.ToString() + "\n  " +Encoding.Unicode.GetString(data, 0, recv) + "\n";
   txtGetMsg.AppendText(recMsg);
   txtGetMsg.Select(txtGetMsgLength, recMsg.Length - Encoding.Unicode.GetString(data, 0, recv).Length - 1);
   txtGetMsg.SelectionColor = Color.Red;
 }), null);
}

如果按下发送消息的按钮, 则发送txtSendMsg中的文本, 我写的是用Unicode编码, 所以可以发送中文字符.


private void btnSendMsg_Click(object sender, EventArgs e)
{
 string input = txtSendMsg.Text;
 if (input == "")
 {
   MessageBox.Show("消息不能为空!", "发送消息出错");
   txtSendMsg.Focus();
 }
 else
 {
   if (meIsClient)
   {
     newclient.Send(Encoding.Unicode.GetBytes(input));
     string showText = "Me:      " + System.DateTime.Now.ToString() + "\n  "
     + input + "\n";
     int txtGetMsgLength = txtGetMsg.Text.Length;
     txtGetMsg.AppendText(showText);
     txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length);
     txtGetMsg.SelectionColor = Color.Blue;
     txtSendMsg.Text = "";
   }
   else
   {
     client.Send(Encoding.Unicode.GetBytes(input));
     string showText = "Me    " + System.DateTime.Now.ToString() + "\n  "
     + input + "\n";
     int txtGetMsgLength = txtGetMsg.Text.Length;
     txtGetMsg.AppendText(showText);
     txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length);
     txtGetMsg.SelectionColor = Color.Blue;
     txtSendMsg.Text = "";
   }
 }
}

程序的运行效果:

基于c#用Socket做一个局域网聊天工具

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

猜你喜欢

  • Android app启动时黑屏或者白屏的原因及解决办法

    2023-06-09 11:32:32
  • Spring Boot实现STOMP协议的WebSocket的方法步骤

    2022-10-01 07:12:27
  • C# ArrayList、HashSet、HashTable、List、Dictionary的区别详解

    2022-06-02 05:22:45
  • logback关闭某个包的日志操作

    2023-04-12 20:16:57
  • java 使用BigDecimal进行货币金额计算的操作

    2023-12-05 23:19:34
  • java中的this引用及对象构造初始化

    2023-03-07 09:38:17
  • Jersey Restful接口如何获取参数的问题

    2023-10-29 14:44:16
  • Java实现一个简易版的多级菜单功能

    2023-08-21 14:33:56
  • Java循环结构之多重循环及continue break

    2023-11-10 15:39:14
  • 详解c# 类的构造方法

    2023-02-10 17:17:19
  • VS.net VSS时,编译报错:未能向文件“.csproj.FileListAbsolute.txt”写入命令行 对路径 的访问被拒绝。

    2021-10-01 18:29:12
  • 通过c++11改进我们的模式之改进命令模式

    2023-03-02 01:58:00
  • Elasticsearch写入瓶颈导致skywalking大盘空白

    2021-07-07 00:39:42
  • Java流程控制语句最全汇总(上篇)

    2023-11-03 01:57:48
  • 基于Java实现双向链表

    2022-11-17 11:39:16
  • struts2实现多文件上传的示例代码

    2022-03-09 23:40:54
  • Android自定义view实现车载可调整轨迹线

    2022-12-06 11:22:21
  • 通过特性(attribute)为枚举添加更多信息示例

    2023-10-10 09:22:06
  • Android横竖屏幕切换小结

    2023-04-15 08:03:20
  • SpringBoot 整合jdbc和mybatis的方法

    2023-08-10 12:51:09
  • asp之家 软件编程 m.aspxhome.com