TCP 通信简单case,Based on Socket(Use in C#/WPF)

  1. 上大学的时候一提到TCP 什么的,Socket什么的就发怵,因为那时还不入门,后面慢慢的就还好,本来是没什么想法的,但是凑巧工作中写了一些TCP 通信的例子,所以下班后简单的整理了一下,希望可以帮助到有需要的童鞋。
  2. 写在前面,写的只是一个demo,里面注释我觉得写的不少了,有问题的欢迎指出或者联系博主。废话不多说了, 直接上代码。
  3. 效果图

     

Server端

using System;
using System.Collections.Generic;
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.Navigation;
using System.Windows.Shapes;

namespace TCPServer
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        string host;
        int port = 8888;//随意啦,0-65535,如果不知道端口有没被占用,打开cmd,输入 netstat -a 即可查看
        Socket serverSocket = null;
        IPHostEntry hostEntry = null; 
        Socket tempClient = null;
        Task taskOfAccept;
        Task taskOfReceive;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Start_Click(object sender, RoutedEventArgs e)
        {
            //This is server start logic
            // use the current host name as the default.
            host = Dns.GetHostName();
             
            //获取主机信息
            hostEntry = Dns.GetHostEntry(host); 

            // Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
            // an exception that occurs when the host IP Address is not compatible with the address family
            // (typical in the IPv6 case).
            IPAddress address = hostEntry.AddressList[2];//Get Current pc IP ,注意这里IPV4和IPV6是有区别,WIFI和网线也有区别,这个可以debug的时候看信息,不是1,就是2
            IPEndPoint ipe = new IPEndPoint(address, port);
            serverSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);//创建使用何种协议的套接字
            serverSocket.Bind(ipe);//绑定ip端口,如果不希望指定端口也是可以的
            serverSocket.Listen(10);//最多监听10个,如果超过10个,多余的会等待或者超时
            listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add(ipe.Address + "Server opened"); }));
            taskOfAccept = new Task(AcceptClient);//因为accept是阻塞主线程的,我们最好不让界面阻塞,所以开启一个线程
            taskOfAccept.Start();
                       
        }

        private void AcceptClient()
        {
            while (true)
            {
                tempClient = serverSocket.Accept();//不断的监听
                listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add( " connected"); }));

                ThreadPool.QueueUserWorkItem(new WaitCallback(Receive),tempClient);//开启线程池,执行receive,因为我们希望是一直收发所以,最好也是加上loop
                //线程池的优点是可以帮你自动管理执行某段函数,缺点呢是不太好控制,一般使用flag来控制,这里因为是个示意,所以没有加
            }       
        }

        private void Receive(object state)
        {
            while (true)
            {
                string dataReceive = string.Empty;
                Byte[] bytesReceived = new Byte[256];
                int bytes = 0;
                // The following will block until the page is transmitted.
                do
                {
                    bytes = tempClient.Receive(bytesReceived, bytesReceived.Length, 0); //不断地get数据一直到get所有的数据
                    dataReceive = dataReceive + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
                    listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Server Received:" + dataReceive); }));
                    dataReceive = string.Empty;
                }
                while (bytes > 0); //如果bytes < 0 是退出了一个客户端,这个可以用来检测客户端的生存状态
            }  
        }

        private void Send_Click(object sender, RoutedEventArgs e)
        {
            string dataSend = string.Empty;
            dataSend = "hello client";
            Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSend);
            tempClient.Send(bytesSent, bytesSent.Length, 0); //Send也是同步阻塞的哦
            listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Server send:" + dataSend); }));
        }

        private void Stop_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                serverSocket.Shutdown(SocketShutdown.Both); //both指停止收发行为,因为我只写了一个client的支持逻辑,如果想一对多,就需要添加全局list来侦听客户端的生存状态
            }
            finally
            {
                serverSocket.Close();
            }
        }
    }
}

Server 端的界面

<Window x:Class="TCPServer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TCPServer" Height="350" Width="525">
    <Grid>
        <Button Content="Start" HorizontalAlignment="Left" Click="Start_Click" Margin="33,46,0,0" VerticalAlignment="Top" Width="75"/>
        <Button Content="Stop" HorizontalAlignment="Left" Click="Stop_Click" Margin="401,46,0,0" VerticalAlignment="Top" Width="75"/>
        <Button Content="Send" HorizontalAlignment="Left" Click="Send_Click" Margin="216,46,0,0" VerticalAlignment="Top" Width="75"/>
        <ListBox Name="listbox" HorizontalAlignment="Left" Height="205" Margin="33,90,0,0" VerticalAlignment="Top" Width="443"/>

    </Grid>
</Window>

Client端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
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.Navigation;
using System.Windows.Shapes;

namespace TCPClient
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        Socket client = null;
        Task taskOfReceiveData;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {
            //Connect
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.Connect("169.254.13.65", 8888); //同步阻塞的哦
            if (client.Connected)
            {
                //Send
                listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add("Connect to Server:169.254.13.65"); }));
                string dataSent = "hello server";
                Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSent);
                client.Send(bytesSent, bytesSent.Length, 0);
            }

            taskOfReceiveData = new Task(receiveData); //一直收
            taskOfReceiveData.Start();



        }

        private void receiveData()
        {
            while (true)
            {
                string dataReceive = string.Empty;
                Byte[] bytesReceived = new Byte[256];
                int bytes = 0;

                // The following will block until the page is transmitted.
                do
                {
                    bytes = client.Receive(bytesReceived, bytesReceived.Length, 0); //不断地get数据一直到get所有的数据
                    dataReceive = dataReceive + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
                    listbox.Dispatcher.Invoke(new Action(() => { this.listbox.Items.Add("Client receive:" + dataReceive); }));
                    dataReceive = "";
                }
                while (bytes > 0);
            }

        }

        private void Send_Click(object sender, RoutedEventArgs e)
        {
            //Send 点一次发一次就行了
            string dataSent = "hello server";
            Byte[] bytesSent = Encoding.ASCII.GetBytes(dataSent);
            client.Send(bytesSent, bytesSent.Length, 0);
            listbox.Dispatcher.BeginInvoke(new Action(() => { this.listbox.Items.Add("Client send:" + dataSent); }));
        }
    }
}

Client 界面

<Window x:Class="TCPClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TCPClient" Height="350" Width="525">
    <Grid>
        <Button Content="Connect" Click="Connect_Click" HorizontalAlignment="Left" Margin="50,50,0,0" VerticalAlignment="Top" Width="75"/>
        <Button Content="Send" Click="Send_Click" HorizontalAlignment="Left" Margin="370,50,0,0" VerticalAlignment="Top" Width="75"/>
        <ListBox Name="listbox" HorizontalAlignment="Left" Height="190" Margin="50,89,0,0" VerticalAlignment="Top" Width="395"/>

    </Grid>
</Window>

有问题直接留言哦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值