(自用留存)C# WPF TCP服务端

非专业人员,因项目需要,要写一个TCP服务端,一个TCP客户端。但在网上搜了好多都没有看见TCP服务端正常关闭的代码,所以把最后写完的代码放上来留作日后备用。如果有更好的实现方式烦请各位赐教或指路。

XML页面:

<Fluent:RibbonWindow x:Class="MyProject.TCP_server"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                     xmlns:Fluent="urn:fluent-ribbon"
                     xmlns:AduSkin="clr-namespace:AduSkin.Controls.Metro;assembly=AduSkin"
                     xmlns:hc="https://handyorg.github.io/handycontrol"
                     mc:Ignorable="d"
                     x:Name="tcp_server"
                     IsIconVisible="False"
                     Height="600"
                     Width="900"
                     WindowStartupLocation="CenterScreen"
                     ResizeMode="CanMinimize"                  
                     Background="#091125"
                     Title="TCP_server"
                     TitleForeground="#091125"
                     Loaded="tcp_server_Loaded"
                     Closing="tcp_server_Closing">

    <Grid>
        <Image Source="Assets/BackGround.png" Stretch="Fill"></Image>
        <Image Source="Assets/TopBottom.png" Stretch="Fill"></Image>
        <TextBlock Foreground="White" FontSize="25" Margin="387,10,386,0" TextWrapping="Wrap" Text="TCP服务端" TextAlignment="Center" Width="130" Height="32" VerticalAlignment="Top" HorizontalAlignment="Center"/>
        <TextBlock x:Name="IPtextBlock" Text="本地ip地址:" Height="20" Width="95" TextWrapping="Wrap" Foreground="White" Background="Transparent" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" Margin="32,75,767,476" MouseLeftButtonDown="IPtextBlock_MouseLeftButtonDown"/>
        <TextBlock Text="本地端口号:" Height="20" Width="100" TextWrapping="Wrap" Foreground="White" Background="Transparent" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" Margin="287,75,507,476"/>
        <ComboBox x:Name="IPtextbox"  Margin="0,0,500,400"  Height="35" Width="150" ItemsSource="{Binding}" Style="{StaticResource ComboBoxStyle}" Foreground="White"  FontSize="16" FontFamily="微软雅黑" FontStretch="Normal"/>
        <!--<TextBox x:Name="IPtextbox" Text="0.0.0.0" Margin="0,0,500,400" Height="35" Width="150" CaretBrush="White" Foreground="White" Background="Transparent" BorderBrush="#00c0ff" BorderThickness="1" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal"/>-->
        <TextBox x:Name="PORTtextbox" Text="20000" Margin="379,68,435,468" Height="35" Width="80" CaretBrush="White" Foreground="White" Background="Transparent" BorderBrush="#00c0ff" BorderThickness="1" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal"/>
        <Button x:Name="MonitorButton" Content="开始监听" Style="{StaticResource Button_Menu}" Width="80" Click="MonitorButton_Click"
                    Margin="471,68,343,468"  Height="35" Foreground="White" Background="Transparent"  FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" />

        <Button x:Name="ClearReceive" Content="清除显示" Style="{StaticResource Button_Menu}" Width="80" Height="33" Click="ClearReceive_Click"
                    Margin="792,284,22,254" Foreground="White" Background="Transparent"  FontSize="16" FontFamily="微软雅黑" FontStretch="Normal"/>

        <Button x:Name="SEND" Content="发送" Style="{StaticResource Button_Menu}" Width="80" Height="33" Click="SEND_Click"
                    Margin="791,458,23,80" Foreground="White" Background="Transparent"  FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" />

        <Button x:Name="ClearSend" Content="清除输入" Style="{StaticResource Button_Menu}" Width="80" Height="33" Click="ClearSend_Click"
         Margin="791,502,23,36" Foreground="White" Background="Transparent"  
         FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" />

        <ComboBox x:Name="clientCombo"  Margin="444,0,0,400"  Height="35" Width="205" Style="{StaticResource ComboBoxStyle}" Foreground="White"  FontSize="16" FontFamily="微软雅黑" FontStretch="Normal"/>
                  <!--ItemsSource="{Binding PortList,Mode = TwoWay,UpdateSourceTrigger = PropertyChanged}"
                  DisplayMemberPath="TargetPort"
                  SelectedValuePath="TargetPort"
                  SelectedItem="{Binding PortList}"-->
                 
        <TextBox x:Name="ReceiveBox" Margin="32,118,122,253" Width="740" Height="200" VerticalAlignment="Center" VerticalContentAlignment="Top" CaretBrush="White" TextWrapping="Wrap" Foreground="White"  Background="Transparent" BorderBrush="#00c0ff" BorderThickness="2" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" VerticalScrollBarVisibility="Auto"/>
        <TextBox x:Name="InputBox" Margin="32,336,122,35" Width="740" Height="200" VerticalAlignment="Center" VerticalContentAlignment="Top" CaretBrush="White" Foreground="White" TextWrapping="Wrap" Background="Transparent" BorderBrush="#00c0ff" BorderThickness="2" FontSize="16" FontFamily="微软雅黑" FontStretch="Normal" VerticalScrollBarVisibility="Auto"/>
        <RadioButton x:Name="sendHEX" Width="50" Height="50" Content="HEX" Style="{StaticResource GroupSelectRadioButton_Left}" Margin="784,378,60,143" IsChecked="True"/>
        <RadioButton x:Name="sendASCII" Width="50" Height="50" Content="ASCII" Style="{StaticResource  GroupSelectRadioButton_Right}" Margin="834,378,10,143"/>


    </Grid>
</Fluent:RibbonWindow>

 后台代码:

using Fluent;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace MyProject
{
    /// <summary>
    /// TCP_server.xaml 的交互逻辑
    /// </summary>
    public partial class TCP_server : Fluent.RibbonWindow
    {
        public static TCP_server TCP_server_;
        public TCP_server()
        {
            TCP_server_ = this;
            InitializeComponent();
        }

        /// <summary>
        /// 负责通信的socket
        /// </summary>
        Socket socketSend;

        /// <summary>
        /// 负责监听Socket
        /// </summary>
        Socket socket;

        /// <summary>
        /// 存放连接的socket
        /// </summary>
        Dictionary<string, Socket> dictionary = new Dictionary<string, Socket>();

        /// <summary>
        /// 用于开机自启选择监听的标志位
        /// </summary>
        private bool SelfStart = false;

        /// <summary>
        /// 线程集合
        /// </summary>
        Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();

        private void tcp_server_Loaded(object sender, RoutedEventArgs e)
        {
            IPAddress[] myip = GetLocalIPv4Address();//加载完成自动获取本机IP
            IPtextbox.ItemsSource = myip;//将本机IP填入下拉框

            ReceiveBox.UndoLimit = 0;//文本框默认可以撤销,但会占用内存,禁用接收文本框的撤销队列,节省内存

            SelfStart = true;//启动时默认选择0.0.0.0监听
            MonitorButton_Click(sender, e);

        }

        /// <summary>
        /// 判断是否开始监听的标志位
        /// </summary>
        private bool isListening = false;

        /// <summary>
        /// 开始监听按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MonitorButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (!isListening) // 如果未监听,则开始监听
                {

                    //创建监听的socket,
                    //SocketType.Stream 流式对应tcp协议
                    //Dgram,数据报对应UDP协议
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    //创建IP地址
                    IPAddress ip;
                    if (SelfStart)
                    {
                        ip = IPAddress.Parse("0.0.0.0"); // 开机自启监控固定IP
                        IPtextbox.Text = ip.ToString();
                        //ip = IPAddress.Any; // 开机默认选择0.0.0.0监听
                    }
                    else
                    {
                        ip = IPAddress.Parse(IPtextbox.Text); // IPAddress.Any;
                    }
         
                    //创建端口号
                    int port = Convert.ToInt32(PORTtextbox.Text);
                    IPEndPoint iPEndPoint = new IPEndPoint(ip, port);

                    //让负责监听的Socket绑定ip和端口号
                    socket.Bind(iPEndPoint);//若是已经监听成功,再次点击“开始监听”,此句会报错,加了try防止报错
                    ShowLog(DateTime.Now + " 监听成功!" + iPEndPoint);//打印日志

                    //设置监听队列
                    socket.Listen(16);//一段时间内可以连接到的服务器的最大数量
                    MonitorButton.Content = "监听中...";

                    isListening = true;

                    Thread thread = new Thread(listen);
                    thread.IsBackground = true;
                    thread.Start(socket);
                }
                else // 如果已经在监听,则关闭监听
                {
                    // 关闭监听线程
                    isListening = false;

                    if (socketSend != null) // 先关闭通信套接字
                    {
                        // 报错“集合已修改;可能无法执行枚举操作。”的解决:1、可在遍历的时候将字典列表.ToArray()转化为数组
                        //                                                   2、可使用另一个List对这两个集合字典进行操作
                        foreach (KeyValuePair<string, Socket> item in dictionary.ToArray()) // 遍历字典里的所有远程终结点,向它们全部发出关闭请求
                        {
                            try
                            {
                                item.Value.Shutdown(SocketShutdown.Both); // 不知道是否能改进:发出关闭请求的之前,应该先终止线程,可能就不会出现“一个封锁操作被对 WSACancelBlockingCall 的调用中断”的异常了?
                                // 从 通信套接字 集合中删除被中断连接的通信套接字;
                                dictionary.Remove(item.Key);
                                // 从通信线程集合中删除被中断连接的通信线程对象;
                                dictThread.Remove(item.Key);
                                //ShowLog(DateTime.Now + "—" + item.Key + "已下线。");
                                //从下拉框集合中删除被中断连接的端口;
                                if (clientCombo.Items.Contains(item.Key))
                                {
                                    this.Dispatcher.Invoke(new Action(delegate
                                    {
                                        clientCombo.Items.Remove(item.Key);
                                    }));
                                }
                            }
                            catch (Exception err)
                            {
                                Console.WriteLine("TCP关闭监听时遍历字典异常:" + err.Message);
                            }

                            item.Value.Close();
                        }

                        this.Dispatcher.Invoke(new Action(delegate
                        {
                            //将下拉框显示的文本置空;
                            clientCombo.Text = null;
                        }));

                        socketSend = null;

                        ShowLog(DateTime.Now + "—" + "服务器已关闭。");

                    }
                    if (socket != null) // 后关闭监听套接字,否则会报错“无法访问已释放的对象”,原因可能是关闭监听后,receive函数会收到来自客户端长度为0的“关闭请求”,导致判断下线要移除终结点时,其已经被释放
                    {
                        socket.Close();

                        socket = null; // 执行后控制台报错:引发的异常:“System.Net.Sockets.SocketException”(位于 System.dll 中)。但目前不影响使用,原因未知。

                    }

                    // 修改按钮状态
                    MonitorButton.Content = "开始监听";
                }
                SelfStart = false;

            }
            catch (Exception ex)
            {
                Console.WriteLine("开始监听点击函数异常:" + ex.Message);
                SelfStart = false;
            }
        }

        /// <summary>
         /// 使用线程来接收数据
         /// </summary>
          /// <param name="o"></param>
        private void listen(object o)
        {
            Socket socket = o as Socket;

            while (isListening)
            {
                try
                {
                    try
                    {
                        socketSend = socket.Accept(); // 监听程序运行到这里处于阻塞状态,直到有客户端连接进来,才会继续往下运行,然后再次运行到此行阻塞等待下一个客户端连接
                    }
                    catch (SocketException ex)
                    {
                        if (ex.SocketErrorCode == SocketError.Interrupted) // 有客户端连接过服务器后,监听程序阻塞在上面,当关闭监听时会继续运行抛出一个中断的异常,在这里接收并处理,用break结束while循环
                        {
                            // 监听线程被关闭
                            Console.WriteLine("Listen函数catch处理if:" + ex.Message);
                            break;
                        }
                        else
                        {
                            Console.WriteLine("Listen函数catch处理else:" + ex.Message);
                        }
                    }
                    //socketSend = socket.Accept(); // 监听程序运行到这里处于阻塞状态,直到有客户端连接进来,才会继续往下运行,然后再次运行到此行阻塞等待下一个客户端连接
                    if (!clientCombo.Items.Contains(socketSend.RemoteEndPoint.ToString()))
                    {
                        this.Dispatcher.Invoke(new Action(delegate
                        {
                            clientCombo.Items.Add(socketSend.RemoteEndPoint.ToString()); // 在下拉框中添加ip地址
                    }));

                    }
                    //负责监听的socket是用来接收客户端连接
                    //创建负责通信的socket
                    //socketSend = socket.Accept();
                    if (!(dictionary.ContainsKey(socketSend.RemoteEndPoint.ToString()) && dictThread.ContainsKey(socketSend.RemoteEndPoint.ToString())))
                    {
                        //创建一个通信线程,通信线程可以解决“客户端异常断开,重连后无法由服务端再向客户端发送数据”的问题
                        ParameterizedThreadStart pts = new ParameterizedThreadStart(receive);
                        //开启新线程,接收客户端发来的信息
                        Thread th = new Thread(pts);
                        th.IsBackground = true;
                        th.Start(socketSend);
                        dictThread.Add(socketSend.RemoteEndPoint.ToString(), th); // 将新建的线程 添加 到线程的集合中去。
                        dictionary.Add(socketSend.RemoteEndPoint.ToString(), socketSend); // 将ip地址添加到字典集合中
                    }

                    ShowLog(DateTime.Now + "—" + socketSend.RemoteEndPoint.ToString() + "已连接");


                }
                catch (Exception error)
                {
                    Console.WriteLine("Listen函数其他异常:" + error.Message);
                }

            }
        }

        /// <summary>
        /// 服务器接收客户端传来的消息
        /// </summary>
        private void receive(object o)
        {
            Socket socketsend = o as Socket;
            while (isListening)
            {
                try
                {
                    //客户端连接成功后,服务器接收客户端发来的消息
                    byte[] buffer = new byte[1024 * 50]; // 50K大小的缓存区。是否隐患?是否每次while循环都会创建一个50K大小的缓冲区?可以释放内存改进吗?
                    //接收到的有效字节数
                    int length = socketsend.Receive(buffer);


                    if (length == 0) // TCP客户端发起“关闭连接”的请求后,挥手两次,receive会一直接收0
                    {
                        try
                        {
                            // 从 通信套接字 集合中删除被中断连接的通信套接字;
                            dictionary.Remove(socketsend.RemoteEndPoint.ToString());
                            // 从通信线程集合中删除被中断连接的通信线程对象;
                            dictThread.Remove(socketsend.RemoteEndPoint.ToString());
                            ShowLog(DateTime.Now + "—" + socketsend.RemoteEndPoint.ToString() + "下线了。");
                            //从下拉框集合中删除被中断连接的端口;
                            if (clientCombo.Items.Contains(socketsend.RemoteEndPoint.ToString()))
                            {
                                this.Dispatcher.Invoke(new Action(delegate
                                {
                                    clientCombo.Items.Remove(socketsend.RemoteEndPoint.ToString());
                                }));
                            }
                            this.Dispatcher.Invoke(new Action(delegate
                            {
                                //将下拉框显示的文本置空;
                                clientCombo.Text = null;
                            }));
                            socketsend.Close(); // 这句话代表服务端也关闭连接,对客户端进行后两次的挥手
                            break; // break结束while循环,本次TCP连接正常关闭
                        }
                        catch (Exception err)
                        {
                            Console.WriteLine("TCP接收到length为0的数据catch异常:" + err);
                            break;
                        }
                    }
                    byte[] newBuffer = new byte[length];
                    Array.ConstrainedCopy(buffer, 0, newBuffer, 0, length);

                    SaveTxt(byteToHexStr(newBuffer)); // 将接收到数据的原始十六进制数存入TXT文件
                    

                    //string str = Encoding.UTF8.GetString(buffer, 0, length); // 以UTF8码接收显示
                    //string str3 = Encoding.Default.GetString(buffer, 0, length); // 以.NET默认编码接收显示
                    string str = byteToHexStr(newBuffer); // 以十六进制接收显示
                    string str2 = Encoding.ASCII.GetString(buffer, 0, length); // 以ASCII码接收显示
                    ShowLog($"\r\n时间:{DateTime.Now},来自端口{socketsend.RemoteEndPoint} ;\r\n以ASCII码显示:{str2}"); // 以ASCII码显示               
                    ShowLog($"\r\n时间:{DateTime.Now},来自端口{socketsend.RemoteEndPoint} ;\r\n以十六进制显示:{str}"); // 以十六进制显示

                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    Console.WriteLine("receive函数异常:" + ex.Message);             
                    break;
                }
            }
        }

        /// <summary>
        /// 显示在文本框,若文本长度超出限制,则清空文本框
        /// </summary>
        /// <param name="str"></param>
        private void ShowLog(string str)
        {
            this.Dispatcher.Invoke(new Action(delegate
            {
                if (ReceiveBox.Text.Length > 1024 * 80) // 如果文本框内容大于80K,大于85000字节的对象被.NET认为是“大对象”,大对象的内存分配和管理方式与一般对象不同,它们通常是在托管堆以外的位置进行内存分配,并且不受垃圾回收的控制。
                {
                    ReceiveBox.Clear(); // 先清除文本框
                }
                ReceiveBox.AppendText(str + "\r\n");

            }));
        }


        /// <summary>
        /// 发送按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SEND_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (clientCombo.Text != null && clientCombo.Text != "")
                {
                    string txt = InputBox.Text;
                    if (sendHEX.IsChecked == true)
                    {
                        byte[] buffer = strToToHexByte(txt); // 默认以十六进制发送
                        string ip = clientCombo.SelectedItem.ToString(); // 获取选中的ip地址
                        Socket send_socket = dictionary[ip];
                        send_socket.Send(buffer);
                    }
                    else if (sendASCII.IsChecked == true)
                    {
                        byte[] buffer = Encoding.ASCII.GetBytes(txt); // 以ASCII码发送
                        string ip = clientCombo.SelectedItem.ToString(); // 获取选中的ip地址
                        Socket send_socket = dictionary[ip];
                        send_socket.Send(buffer);
                    }
                }
                else
                {
                    HandyControl.Controls.MessageBox.Show("未选择发送目标端口", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("发送按钮点击函数异常:" + ex.Message);
            }

        }

        /// <summary>
        /// 发送函数
        /// </summary>
        public bool SendMsg(string deviceID, string comID, byte[] msg)
        {
            try
            {
                SQL se = new SQL();
                string sql = "自己的一句SQL语句";
                DataTable data = se.ExecuteDatable(sql);
                string b = data.Rows[0][0].ToString();
                //将控件的选项置为数据库中绑定过的端口号,此句执行成功的前提是:下拉框中已经有这一项,否则执行无效,将仍然保持执行前的状态
                clientCombo.SelectedItem = data.Rows[0][0].ToString();
                if (clientCombo.SelectedItem != null) // 判断是否选择了客户端,如果是,执行下一步操作
                {
                    string ip = clientCombo.SelectedItem.ToString(); // 获取选中的ip地址
                    Socket socketsend = dictionary[ip];
                    socketsend.Send(msg);
                    return true;
                }
                else
                {
                    HandyControl.Controls.MessageBox.Show("未选择目标客户端", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("SendMsg函数异常:" + ex.Message);
                return false;
            }

        }



        /// <summary>
        /// 字符串转16进制格式,不够自动前面补零
        /// </summary>
        private static byte[] strToToHexByte(String hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
                }
                catch
                {
                    HandyControl.Controls.MessageBox.Show("含有非16进制字符", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                    return null;
                }
                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    HandyControl.Controls.MessageBox.Show("含有非16进制字符", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                    return null;
                }
                return returnBytes;
            }
        }


        /// <summary>
        /// 字节数组转16进制字符串
        /// </summary>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            try
            {
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                        returnStr += " ";//两个16进制用空格隔开,方便看数据
                    }
                }
                return returnStr;
            }
            catch (Exception)
            {
                return returnStr;
            }
        }


        /// <summary>
        /// 清除接收显示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearReceive_Click(object sender, RoutedEventArgs e)
        {
            ReceiveBox.Clear();
        }

        /// <summary>
        /// 清除发送输入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearSend_Click(object sender, RoutedEventArgs e)
        {
            InputBox.Clear();
        }

        /// <summary>
        /// 关闭时执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tcp_server_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true; // 禁止关闭TCP服务端
        }

        /// <summary>
        /// IPtextBlock单击事件,将本机IP填入文本框中
        /// </summary>
        private void IPtextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            IPAddress[] ip = GetLocalIPv4Address();
            IPtextbox.ItemsSource = ip;
        }

        /// <summary>
        /// 获取本地IPv4地址
        /// </summary>
        /// <returns></returns>
        IPAddress[] GetLocalIPv4Address()
        {
            IPAddress[] localIpv4 = new IPAddress[Dns.GetHostAddresses(Dns.GetHostName()).Length + 2];
            //获取本机所有的IP地址列表
            IPAddress[] IpList = Dns.GetHostAddresses(Dns.GetHostName());
            int i = 0;
            //循环遍历所有IP地址
            foreach (IPAddress IP in IpList)
            {
                //判断是否是IPv4地址
                if (IP.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIpv4[i] = IP;
                    i++;
                }
                else
                {
                    continue;
                }
            }
            localIpv4[localIpv4.Length - 1] = IPAddress.Parse("0.0.0.0");
            localIpv4[localIpv4.Length - 2] = IPAddress.Parse("127.0.0.1");

            //将数组中的null值去除
            localIpv4 = localIpv4.Where(x => !string.IsNullOrEmpty(Convert.ToString(x))).ToArray();
            //localIpv4 = localIpv4.Where(x => !string.IsNullOrWhiteSpace(Convert.ToString(x))).ToArray();
            return localIpv4;
        }

        /// <summary>
        /// 将原始数据保存为TXT文件
        /// </summary>
        private void SaveTxt(string strLog)
        {
            string sFilePath = System.AppDomain.CurrentDomain.BaseDirectory + "/TCP原始数据/"; // 找到Debug文件夹中的“TCP原始数据”文件夹
            string sFileName = DateTime.Now.ToString("yyyyMMdd") + ".txt"; // 在文件夹中创建以当前系统时间命名的.txt文件
            sFileName = sFilePath + "\\" + sFileName; // 文件的绝对路径
            if (!Directory.Exists(sFilePath)) // 验证路径是否存在
            {
                Directory.CreateDirectory(sFilePath); // 不存在则创建
            }
            FileStream fs;
            StreamWriter sw;
            if (File.Exists(sFileName))
            //验证文件是否存在,有则追加,无则创建
            {
                fs = new FileStream(sFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
            }
            else
            {
                fs = new FileStream(sFileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            }
            sw = new StreamWriter(fs);
            sw.WriteLine("【" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + "】" + "\r\n" + strLog);//写入日志的内容
            sw.Close();
            fs.Close();
        }

    }
}

后台代码的一些注释中提出了疑问,不知是否可以作为改进的点?或者是否可以有更好的代码逻辑实现?希望看见的大佬不吝赐教!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的 WPF 客户端和服务端 TCP 通信的示例代码: 服务端代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Server { class Program { static void Main(string[] args) { TcpListener server = null; try { // Set the TcpListener on port 13000. Int32 port = 13000; IPAddress localAddr = IPAddress.Parse("127.0.0.1"); // TcpListener server = new TcpListener(port); server = new TcpListener(localAddr, port); // Start listening for client requests. server.Start(); // Buffer for reading data Byte[] bytes = new Byte[256]; String data = null; // Enter the listening loop. while (true) { Console.Write("Waiting for a connection... "); // Perform a blocking call to accept requests. // You could also use server.AcceptSocket() here. TcpClient client = server.AcceptTcpClient(); Console.WriteLine("Connected!"); data = null; // Get a stream object for reading and writing NetworkStream stream = client.GetStream(); int i; // Loop to receive all the data sent by the client. while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { // Translate data bytes to a ASCII string. data = Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("Received: {0}", data); // Process the data sent by the client. data = data.ToUpper(); byte[] msg = Encoding.ASCII.GetBytes(data); // Send back a response. stream.Write(msg, 0, msg.Length); Console.WriteLine("Sent: {0}", data); } // Shutdown and end connection client.Close(); } } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } finally { // Stop listening for new clients. server.Stop(); } Console.WriteLine("\nHit enter to continue..."); Console.Read(); } } } ``` 客户端代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Client { class Program { static void Main(string[] args) { string server = "127.0.0.1"; int port = 13000; try { TcpClient client = new TcpClient(server, port); // Translate the passed message into ASCII and store it as a Byte array. string message = "Hello, server!"; byte[] data = Encoding.ASCII.GetBytes(message); // Get a client stream for reading and writing. // Stream stream = client.GetStream(); NetworkStream stream = client.GetStream(); // Send the message to the connected TcpServer. stream.Write(data, 0, data.Length); Console.WriteLine("Sent: {0}", message); // Receive the TcpServer.response. // Buffer to store the response bytes. data = new byte[256]; // String to store the response ASCII representation. string responseData = string.Empty; // Read the first batch of the TcpServer response bytes. int bytes = stream.Read(data, 0, data.Length); responseData = Encoding.ASCII.GetString(data, 0, bytes); Console.WriteLine("Received: {0}", responseData); // Close everything. stream.Close(); client.Close(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } Console.WriteLine("\nHit enter to continue..."); Console.Read(); } } } ``` 这里使用了 .NET Framework 自带的 TCP 相关类,服务端使用 `TcpListener` 监听客户端连接,客户端使用 `TcpClient` 连接服务器,使用 `NetworkStream` 进行数据通信。注意修改 IP 地址和端口号以适应您的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值