TCP/IP协议——使用TcpListener和Tcpclient类实现通信

目录

TcpListener和TcpClient

TcpListener和TcpClient的使用

连接到服务器

创建服务器套接字

接收服务器连接

创建 `NetworkStream`​​ 以发送和接收数据

关闭连接

使用TcpListener搭建Tcp服务器

TcpClient用于客户端和服务器连接


TcpListener和TcpClient

在C#中实现TCP通信,你可以使用 System,Net.Sockets 命名空间中的 TcpListener 和
Tcpclient 类。

若要使用传输控制协议(TCP),有两个选项:使用 Socket以获得最大控制和性能,或使用 Icpclient 和IcpListener 帮助程序类。Icpclien 和 IcpListener 是在System.Net.Sockets.Socket 类的基础上建立的,并负责传输数据的详细信息以便于使用。

TcpListener和TcpClient的使用

连接到服务器

​`TcpClient`​ 中的所有 `Connect`​、`ConnectAsync`​、`BeginConnect`​ 和 `EndConnect`​ 重载在功能上都等效于相应的 `Socket`​ 方法。

请考虑以下 TCP 客户端代码:

    var client = new TcpClient();
    client.Connect("www.example.com", 80);

上述 `TcpClient`​ 代码等效于以下套接字代码:

    var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
    socket.Connect("www.example.com", 80);

创建服务器套接字

就像与原始 `Socket`​ 对应项功能等效的 `TcpClient`​ 实例一样,本部分将 `TcpListener`​ 构造函数映射到其相应的套接字代码。 要考虑的第一个构造函数是 `TcpListener(IPAddress localaddr, int port)`​。

var listener = new TcpListener(IPAddress.Loopback, 5000);

前面的 TCP 侦听器代码在功能上等效于下面的套接字代码:

var ep = new IPEndPoint(IPAddress.Loopback, 5000);
var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

开始侦听服务器

Start()方法是组合 socket 的 Bind 和 Listen() 功能的包装器

var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start(10);

前面的 TCP 侦听器代码在功能上等效于下面的套接字代码:

var endPoint = new IPEndPoint(IPAddress.Loopback, 5000);
var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
socket.Listen(10);

接收服务器连接

在后台,传入的TCP 连接在接受时始终会创建新的套接字。 TcpListener 可以直接接受 socket实例(通过 Acceptsocketl)或 AceptsocketAsymc),也可以接受 IcpClient(通过AcceptTcpClient()和AcceptTcpClientAsync())。

var listener = new TcpListener(IPAddress.Loopback, 5000);
var acceptedSocket = await listener.AcceptSocketAsync();

前面的 TCP 侦听器代码在功能上等效于下面的套接字代码:

var endPoint = new IPEndPoint(IPAddress.Loopback, 5000);
var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var acceptedSocket = await socket.AcceptAsync();

创建 `NetworkStream`​​ 以发送和接收数据

使用 Tcpclient 时,需要使用 Getstream()方法实例化NetworkStream,以便能够发送和接收数据。使用socket 时,必须手动创建 Networkstream

var client = new TcpClient();
NetworkStream stream = client.GetStream();

等效于以下套接字代码:

var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
var stream = new NetworkStream(socket, ownsSocket: true);

如果代码不需要使用 stream 实例,则可以直接依赖 scket 的发送/接收方法(Send、SendAsync、Receive和 ReceveAsync),而不是创建 Networkstream.

关闭连接

使用 `TcpClient`​ 时,需要使用 Close()方法关闭连接,

var client = new TcpClient();
client.Close();

使用TcpListener搭建Tcp服务器

    TcpListener listener;
    Dictionary<string, TcpClient> clientList = new Dictionary<string, TcpClient>();
    
    private void button1_Click(object sender, EventArgs e)
    {
        // 按钮状态
        openBtn.Enabled = false;
        closeBtn.Enabled = true;
    
        // 1.创建监听对象
        listener = new TcpListener(IPAddress.Any, 3030);
        // 2.开始监听(backlog:链接最大的挂起数)
        listener.Start(100);
        startListener(listener);
    
    }
    private void startListener(TcpListener lis)
    {
        // 3.等待链接(接收挂起的连接请求)
        Task.Run(() =>
        {
            while (true)
            {
                try
                {
                    TcpClient client = lis.AcceptTcpClient();
                    string ip = client.Client.RemoteEndPoint.ToString(); // 获取连接客户的IP
                    clientList.Add(ip, client);
                    startReceive(client.GetStream(), ip);
                    addRichTextBox($"{ip}已经连接到服务器");
                }
                catch (Exception ex)
                {
                    lis.Stop();
                    break;
                }
            }
        });
    }
    private void startReceive(NetworkStream stream, string ip)
    {
        Task.Run(() =>
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024];  // 大小按情况而定
                    int length = stream.Read(buffer, 0, buffer.Length);  // 返回本次接收数据的字节数
                    if (length == 0)
                    {
                        throw new Exception($"客户端{ip}断开连接");
                    }
                    else
                    {
                        string value = Encoding.Default.GetString(buffer, 0, length);
                        addRichTextBox($"接收到{ip}发送的消息:{value}\r\n");
                    }
                }
                catch
                {
                    // 从字典中移除当前连接
                    clientList.Remove(ip);
                    addRichTextBox($"{ip}连接已断开\r\n");
                    break;
                }
            }
        });
    }
    // 发送信息给客户端
    private void sendBtn_Click(object sender, EventArgs e)
    {
        byte[] bytes = Encoding.Default.GetBytes(msgTextbox.Text);
        // 循环所有的客户端发送数据(也可以根据IP选择给谁发送)
        foreach (var item in clientList)
        {
            item.Value.GetStream().Write(bytes, 0, bytes.Length);
        }
    }
    // 关闭按钮点击
    private void closeBtn_Click(object sender, EventArgs e)
    {
        // 控制按钮状态
        closeBtn.Enabled = false;
        openBtn.Enabled = true;
    
        foreach (var item in clientList)
        {
            TcpClient client = item.Value;
            client.Close();
        }
        listener.Stop();
    }
    private void addRichTextBox(string text)
    {
        richTextBox1.Invoke(new Action(() =>
        {
            richTextBox1.AppendText(text);
            // 让rich滚动到最下面
            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            richTextBox1.ScrollToCaret();
        }));
    }

TcpClient用于客户端和服务器连接

简单代码示例如下

    private TcpClient tcpClient;
    private void button1_Click(object sender, EventArgs e)
    {
        // 1.创建客户端对象
        tcpClient = new TcpClient();
        // 2.开始链接
        tcpClient.Connect(IPAddress.Parse("127.0.0.1"),3030);
        // 3.获取数据流 Stream(读read 和 写write)
        NetworkStream stream = tcpClient.GetStream();
        // 4. 开启分线程
        Thread thread = new Thread(ClientThread);
        thread.Start(stream);
    }
    // 开分线程,收发消息
    private void ClientThread(object obj)
    {
        NetworkStream stream = obj as NetworkStream;
        while (true)
        {
            // 5.向服务器发送消息(自定义一个带输入框的对话框)
            string info = "张三发送的消息";
            byte[] bytes = Encoding.UTF8.GetBytes(info);
            stream.Write(bytes,0,bytes.Length);
    
            // 6.接收来自服务器的消息
            byte[] buffer = new byte[1024];
            int length = stream.Read(buffer,0,buffer.Length);
            string msg = Encoding.UTF8.GetString(buffer,0,length);
            MessageBox.Show(msg);
        }
    }

‍

本篇文章部分参考于网络,如有侵权请联系本人删除!!!

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值