服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 基于c#用Socket做一个局域网聊天工具

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

2021-12-08 13:14Create Chen C#

目前基于Internet的即时聊天工具已经做的非常完美,本文介绍了基于c#用Socket做一个局域网聊天工具,有需要的朋友可以看一下。

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

作为服务端, 要声明一个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.

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

服务端代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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();
    }
  }
}

客户端代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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中显示出来:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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编码, 所以可以发送中文字符.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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做一个局域网聊天工具

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

延伸 · 阅读

精彩推荐
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25