C# Socket网络编程

入门级C# Socket编程实现

只要知道要通信的两台主机的IP地址和进程的端口号,然后可以用Socket让这两个进程进行通信。

在本机上运行服务端和客户端,ip为127.0.0.1,使用端口9050(0~1023的端口号通常用于一些比较知名的网络服务和应用,普通网络应用程序则应该使用1024以上的端口号,以避免该端口号被另一个应用或系统服务使用)。

服务端:

var ip   = "127.0.0.1";
var port = 9050;
//第一步:建立一个用于通信的Socket对象
//参数1:指定该IP对应的协议,此为IPv4;参数2:定义要打开的Socket的类型;参数3:向Windows Sockets API通知所请求的协议
var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//第二步:使用bind绑定IP地址和端口号,IPEndPoint内参数为IPAddress的long类型和端口号
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
serverSocket.Bind(ipEndPoint);

//第三步:使用listen监听客户端,参数为指定侦听队列的容量
serverSocket.Listen(10);

//第四步:使用accept中断程序直到连接上客户端,(接收连接并返回一个新的Socket,Accept会中断程序,直到有客户端连接)
Console.WriteLine("等待客户端连接...");
var socket   = serverSocket.Accept();
var socketip = (IPEndPoint) socket.RemoteEndPoint;
Console.WriteLine($"连接成功! ip:{socketip.Address}  端口:{socketip.Port}");

//第五步:接收来自客户端的请求,用死循环来不断的从客户端获取信息
while (true)
{
    var receiveBytes = new byte[1024];
    var receive      = socket.Receive(receiveBytes);
    if (receive == 0 || Encoding.UTF8.GetString(receiveBytes, 0, receive) == "exit") //当信息长度为0或收到exit,说明客户端连接断开
    {
        break;
    }

    Console.WriteLine(Encoding.UTF8.GetString(receiveBytes, 0, receive)); //将指定字节数组中的一个字节序列解码为一个字符串
}

//第六步:返回客户端的数据
var send = new byte[1024];
send = Encoding.UTF8.GetBytes("服务端已关闭!");
socket.Send(send);

//第七步:如果接收到客户端已关闭连接信息就关闭服务器端,并返回信息
serverSocket.Close();
socket.Close();
Console.WriteLine("服务端关闭...");

客户端:

var ip   = "127.0.0.1";
var port = 9050;
//第一步:建立一个用于通信的Socket对象
var ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//第二步:根据指定的IP和端口连接服务器
//IPAddress:包含了一个IP地址;IPEndPoint:包含了一对IP地址(IPAdress类型)和端口号
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
ClientSocket.Connect(ipEndPoint);

//第三步:连接成功后向服务器端发送数据请求
while (true)
{
    var send = new byte[1024];
    Console.WriteLine("请输入要发送的数据:");
    var str = Console.ReadLine();
    send = Encoding.UTF8.GetBytes(str);
    ClientSocket.Send(send);
    if (str == "exit")
    {
        Console.WriteLine("已退出...");
        break;
    }

    Console.WriteLine("发送成功!" + "\n");
}

//第四步:接收服务器返回的请求数据
var receiveBytes = new byte[1024];
var receive      = ClientSocket.Receive(receiveBytes);
Console.WriteLine(Encoding.UTF8.GetString(receiveBytes, 0, receive));

//第五步:如果不需要请求数据就关闭客户端并给服务器发送关闭连接信息
ClientSocket.Close();

通讯:

 

 

public class CodeScanner_Socket : NotifyPropertyChanged
{
    public Socket ClientSocket;
    public string ip, port;
    private string _ReceivedText = string.Empty;
    private Task task;
    private BackgroundWorker backgroundWorker;
    private bool IsReceived = false;

    public CodeScanner_Socket(string ip, string port)
    {
        this.ip = ip;
        this.port = port;
    }

    /// <summary>
    /// 接收到的数据
    /// </summary>
    public string ReceivedText
    {
        get => _ReceivedText;
        set
        {
            _ReceivedText = value;
            OnPropertyChanged();
        }
    }

    /// <summary>
    /// 判断是否已连接,true已连接;false未连接
    /// </summary>
    /// <returns></returns>
    public virtual bool IsSocketConnected()
    {
        if (ClientSocket != null)
        {
            try
            {
                // 尝试发送一个空字节数组来检查连接
                byte[] emptyBuffer = new byte[0];
                ClientSocket.Send(emptyBuffer);
                // 如果没有抛出异常,则可能认为Socket是连接的
                return true;
            }
            catch (SocketException ex)
            {
                // 检查特定的错误代码
                switch (ex.ErrorCode)
                {
                    case (int)System.Net.Sockets.SocketError.ConnectionReset:
                    case (int)System.Net.Sockets.SocketError.ConnectionAborted:
                    case (int)System.Net.Sockets.SocketError.NotConnected:
                        // 这些错误通常表示连接已经断开
                        PlateLogOperator.Info($"Socket is not connected.\r\nCaught ErrorCode:{ex.ErrorCode}");
                        break;

                    default:
                        // 处理其他类型的SocketException
                        PlateLogOperator.Info("Socket exception occurred: " + ex.Message);
                        break;
                }
                return false;
            }
        }
        return false;
    }

    /// <summary>
    /// 连接
    /// </summary>
    /// <param name="ip">IP地址</param>
    /// <param name="Port">端口号</param>
    /// <returns></returns>
    public virtual bool SocketConnect()
    {
        try
        {
            if (IsSocketConnected())
            {
                PlateLogOperator.Warn("已连接...");
                return true;
            }

            var port_int = Convert.ToInt32(port);
            ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port_int);
            ClientSocket.Connect(ipEndPoint);

            //task = Task.Factory.StartNew(() =>
            //{
            //    ClientReceived();
            //}, TaskCreationOptions.LongRunning);
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += ClientReceived;
            backgroundWorker.WorkerSupportsCancellation = true; //允许取消
            backgroundWorker.RunWorkerAsync();                   //开始执行DoWork
            return true;
        }
        catch (Exception e)
        {
            PlateLogOperator.Error($"发生错误,原因:{e.Message} 位置:{e.StackTrace.Substring(e.StackTrace.Length - 6)}");
            ClientSocket = null;
            return false;
        }
    }

    /// <summary>
    /// 断开连接
    /// </summary>
    /// <returns></returns>
    public virtual bool SocketDisConnect()
    {
        try
        {
            if (ClientSocket != null && IsSocketConnected())
            {
                ClientSocket.Shutdown(SocketShutdown.Both);
                ClientSocket.Close();
                ClientSocket = null;
                return true;
            }
            return false;
        }
        catch (Exception e)
        {
            PlateLogOperator.Error(e.Message);
            return false;
        }
    }

    /// <summary>
    /// 客户端发送数据,可重写
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public virtual bool ClientSend(string str)
    {
        try
        {
            var send = new byte[1024];
            send = Encoding.UTF8.GetBytes(str);
            //send = Encoding.ASCII.GetBytes(str);
            if (ClientSocket != null && IsSocketConnected())
            {
                ClientSocket.Send(send);
            }
            else
            {
                PlateLogOperator.Warn("客户端未连接!!!");
                return false;
            }
            return true;
        }
        catch (Exception e)
        {
            PlateLogOperator.Error(e.Message);
            return false;
        }
    }

    /// <summary>
    /// 接收服务端传过来的数据
    /// </summary>
    public virtual void ClientReceived(object sender, DoWorkEventArgs e)
    {
        try
        {
            while (!backgroundWorker.CancellationPending)
            {
                if (ClientSocket.Poll(10, SelectMode.SelectRead))
                {
                    backgroundWorker.CancelAsync(); //停止执行DoWork
                    break;
                }

                var buffer = new byte[4096];
                var nRevBufCnt = ClientSocket.Receive(buffer);
                if (nRevBufCnt <= 0)
                    break;

                IsReceived = true;
                ReceivedText = Encoding.UTF8.GetString(buffer, 0, nRevBufCnt);
            }

            ClientSocket.Shutdown(SocketShutdown.Both);
            ClientSocket.Close();
            ClientSocket = null;
        }
        catch (Exception ex)
        {
            //PlateLogOperator.Error("ClientReceived:" + ex.Message);
            ClientSocket?.Shutdown(SocketShutdown.Both);
            ClientSocket?.Close();
            ClientSocket = null;
            ReceivedText = null;
        }
    }

    /// <summary>
    /// 处理返回的数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="RtnMsg"></param>
    /// <returns></returns>
    public virtual string RtnMsgConvert()
    {
        if (IsReceived)
        {
            IsReceived = false;
            return ReceivedText;
        }

        return string.Empty;
    }
}
posted @ 2023-10-31 09:34  时而有风  阅读(55)  评论(0编辑  收藏  举报