• C#使用TcpListener进行聊天通信


    进行通信分为2部分,一个是服务端,一个是客户端。

    TcpListener是对socket的封装,更容易进行控制,底层依然是socket。

    一,服务端

    1.使用TcpListener实例化,得到服务器的ip和端口 

    myListener = new TcpListener(IPAddress.Parse(textBox1.Text), Convert.ToInt32(textBox2.Text)); 

    2.启动TcpListener

    myListener.Start();   

    3.创建一个线程 

    Thread myThread = new Thread(ListenClientConnect); 

    4.让这个线程,不停的监听客户端的请求

    newClient = myListener.AcceptTcpClient();

    5.从网络流中获得客户端的消息

     receiveString = user.br.ReadString();

    6.把流写入给user

     user.bw.Write(message);  user.bw.Flush();

    7. 停止监听

    myListener.Stop();

    二,客户端

    1.实例化

    client = new TcpClient();

    2.连接服务器

    client.Connect(IPAddress.Parse(textBox3.Text), Convert.ToInt32(textBox2.Text));

    3.获取网络流

    NetworkStream networkStream = client.GetStream();

    4.将网络流作为二进制读写对象

    br = new BinaryReader(networkStream);bw = new BinaryWriter(networkStream);

    5.读取服务器的流,接收消息

    receiveString = br.ReadString();

    6.向服务器写流,发送消息

     bw.Write(message);

    7.释放资源,关闭连接

    br.Close();

    bw.Close();

    client.Close();

    信息传递的流程:

    客户端登录
    服务器监听
    客户端发送消息
    服务器收到消息


    服务器收到消息后,把消息发给客户端
    服务器又监听了(消息空了)

    客户端收到消息
    客户端又监听了  

    拓展核心代码:

    使用NetworkStream类,把流分别给BinaryReader读,BinaryWriter写。

    必须按顺序  写  流

    必须按顺序  读  流

    服务器

    1. using System;
    2. using System.IO;
    3. using System.Net;
    4. using System.Net.Sockets;
    5. using System.Text;
    6. namespace ConsoleApp2
    7. {
    8. /// <summary>
    9. /// 服务端监听客户端信息,一旦有发送过来的信息,便立即处理
    10. /// </summary>
    11. class Program
    12. {
    13. //全局TcpClient
    14. static TcpClient client;
    15. //文件流建立到磁盘上的读写流
    16. static FileStream fs = new FileStream(@"D:\demo\6.jpg", FileMode.Create);
    17. //buffer
    18. static int bufferlength = 200;
    19. static byte[] buffer = new byte[bufferlength];
    20. //网络流
    21. static NetworkStream ns;
    22. static BinaryReader br;
    23. static void Main(string[] args)
    24. {
    25. ConnectAndListen();
    26. }
    27. static void ConnectAndListen()
    28. {
    29. //服务端监听任何IP 但是端口号是80的连接
    30. TcpListener listener = new TcpListener(IPAddress.Any, 8083);
    31. //监听对象开始监听
    32. listener.Start();
    33. while (true)
    34. {
    35. Console.WriteLine("等待连接");
    36. //线程会挂在这里,直到客户端发来连接请求
    37. client = listener.AcceptTcpClient();
    38. Console.WriteLine("已经连接");
    39. //得到从客户端传来的网络流
    40. ns = client.GetStream();
    41. br = new BinaryReader(ns);
    42. //如果网络流中有数据
    43. if (ns.DataAvailable)
    44. {
    45. //同步读取网络流中的byte信息
    46. //do
    47. //{
    48. // ns.Read(buffer, 0, bufferlength);
    49. //} while (ns.Length > 0);
    50. string s = br.ReadString();
    51. bool b = br.ReadBoolean();
    52. // byte[] dataArray = br.ReadBytes(100000); //这里长度不对的话,会报错。
    53. br.BaseStream.BeginRead(buffer, 0, bufferlength, ReadAsyncCallBack, null);
    54. //byte[] dataArray = br.ReadBytes(br.BaseStream.ReadByte()); //这里长度不对的话,会报错。
    55. //string sb = Encoding.Default.GetString(dataArray, 0, dataArray.Length);
    56. //异步读取网络流中的byte信息
    57. //ns.BeginRead(buffer, 0, bufferlength, ReadAsyncCallBack, null);
    58. }
    59. }
    60. }
    61. /// <summary>
    62. /// 异步读取
    63. /// </summary>
    64. /// <param name="result"></param>
    65. static void ReadAsyncCallBack(IAsyncResult result)
    66. {
    67. int readCount;
    68. //获得每次异步读取数量
    69. readCount = client.GetStream().EndRead(result);
    70. //如果全部读完退出,垃圾回收
    71. if (readCount < 1)
    72. {
    73. client.Close();
    74. ns.Dispose();
    75. fs.Dispose();
    76. return;
    77. }
    78. //将网络流中的图片数据片段顺序写入本地
    79. fs.Write(buffer, 0, 200);
    80. //再次异步读取
    81. //ns.BeginRead(buffer, 0, 200, ReadAsyncCallBack, null);
    82. br.BaseStream.BeginRead(buffer, 0, 200, ReadAsyncCallBack, null);
    83. }
    84. }
    85. }

    客户端:

    1. using System;
    2. using System.IO;
    3. using System.Net;
    4. using System.Net.Sockets;
    5. using System.Text;
    6. namespace ConsoleApp1
    7. {
    8. class Program
    9. {
    10. /// <summary>
    11. /// 客户端
    12. /// </summary>
    13. /// <param name="args"></param>
    14. static void Main(string[] args)
    15. {
    16. SendImageToServer(@"D:\demo\1\1.jpg");
    17. }
    18. static void SendImageToServer(string imgURl)
    19. {
    20. if (!File.Exists(imgURl)) return;
    21. //创建一个文件流打开图片
    22. FileStream fs = File.Open(imgURl, FileMode.Open);
    23. //声明一个byte数组接受图片byte信息
    24. byte[] fileBytes = new byte[fs.Length];
    25. using (fs)
    26. {
    27. //将图片byte信息读入byte数组中
    28. fs.Read(fileBytes, 0, fileBytes.Length);
    29. fs.Close();
    30. }
    31. //找到服务器的IP地址
    32. IPAddress address = IPAddress.Parse("127.0.0.1");
    33. //创建TcpClient对象实现与服务器的连接
    34. TcpClient client = new TcpClient();
    35. //连接服务器
    36. client.Connect(address, 8083);
    37. using (client)
    38. {
    39. //连接完服务器后便在客户端和服务端之间产生一个流的通道
    40. NetworkStream ns = client.GetStream();
    41. BinaryWriter bw;
    42. using (ns)
    43. {
    44. bw = new BinaryWriter(ns);
    45. //通过此通道将图片数据写入网络流,传向服务器端接收
    46. bw.Write("123");
    47. bw.Write(false);
    48. //StringBuilder sb1 = new StringBuilder();
    49. //sb1.Append("456");
    50. //byte[] dataArray = Encoding.Default.GetBytes(sb1.ToString());
    51. //bw.Write(dataArray,0, dataArray.Length);
    52. bw.Write(fileBytes, 0, fileBytes.Length);
    53. //ns.Write(fileBytes, 0, fileBytes.Length);
    54. //ns.Write("123");
    55. }
    56. }
    57. }
    58. }
    59. }

    文字使用br.ReadString()传递。

    图片使用数组字节传递

    1. byte[] data = ImageToByte(pictureBox1.Image);
    2. //对原始的数据数组加上协议的头部字节
    3. byte[] result = new byte[data.Length + 1];
    4. //设置当前的协议头部字节是1:代表字符串
    5. result[0] = 3; //发送
    6. //把原始的数据放到最终的字节数组里去
    7. Buffer.BlockCopy(data, 0, result, 1, data.Length);
    8. ClientSocekt.Send(result, 0, result.Length, SocketFlags.None);

  • 相关阅读:
    C# 第三方曲线库及其特点
    基于Python的招聘岗位数据分析系统的设计与实现
    nginx降权+匹配php
    flink测试redis sink报错
    WPF下实现拖动任意地方都可以拖动窗口
    如何封装Dao_java培训
    miniob源码 架构概览
    人工智能基础_机器学习003_有监督机器学习_sklearn中线性方程和正规方程的计算_使用sklearn解算八元一次方程---人工智能工作笔记0042
    【算法刷题日记之本手篇】跳台阶扩展问题与快到碗里来
    简述ES6新特性 (前端面试题)
  • 原文地址:https://blog.csdn.net/u012563853/article/details/125367492