C# 使用 Socket (Udp + Tcp)

以一些示例,记录 C# 中如何使用Socket:

目录

1.第一个示例,使用.net 自带的 Socket 纯手工写 (Udp协议)

2.第二个示例,使用.net 自带的 Socket 纯手工写 (Tcp协议)

3.第三个示例,直接使用WebSocket【推荐使用】


1.第一个示例,使用.net 自带的 Socket 纯手工写 (Udp协议)

这个方式灵活性高,但不建议使用:

这个示例的作用是:服务端和客户端,可以互相收发消息,如上图。我用的本机测试的,所以用了两个端口来监听。如果是不同机器且连着内网或公网,只需一个监听端口,但要换成对应的局域网ip或者公网映射ip.

步骤:

1.新增个空解决方案,并添加两个winform项目,一个是 server 端一个是 client 端:

2.在服务端和客户端分别加入如下代码:

服务端:

public partial class Server : Form
{
    private readonly Socket _listenSocket;

    private EndPoint _listenPort = new IPEndPoint(IPAddress.Any, 7942);
    private EndPoint _testClientPort = new IPEndPoint(IPAddress.Parse("192.168.2.32"), 7943);

    //数据
    private byte[] _buffer = new byte[1024];

    //数据(字符串)
    private string _chatString = string.Empty;

    //客户端ip+端口
    private EndPoint _clientIpPort;

    //定个委托
    public delegate void ShowDataDelegate();

    public Server()
    {
        InitializeComponent();

        _listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        _listenSocket.Bind(_listenPort);//本机用Bind,远程用Connect
        _listenSocket.BeginReceiveFrom(_buffer, 0, 1024, SocketFlags.None, ref _listenPort, ReceiveData, _listenSocket);
    }

    private void ShowData()
    {
        if (!string.IsNullOrEmpty(_chatString))
        {
            this.richTextBox.AppendText($"客户端({_clientIpPort}): {_chatString}\n");
        }
    }

    private void ReceiveData(IAsyncResult ar)
    {
        // 创建ip+port
        var sender = new IPEndPoint(IPAddress.Any, 0);
        var tempRemoteEp = (EndPoint)sender;

        //获取socket
        var socket = (Socket)ar.AsyncState;

        //获取客户端发来的数据(客户端ip+port在第二个参数中)
        var recv = socket.EndReceiveFrom(ar, ref tempRemoteEp);

        //客户端ip+端口
        _clientIpPort = tempRemoteEp;

        //将数据流转成字符串
        _chatString = Encoding.Unicode.GetString(_buffer, 0, recv);
        richTextBox.Invoke(new ShowDataDelegate(ShowData));

        if (!this.IsDisposed)
        {
            _listenSocket.BeginReceiveFrom(_buffer, 0, 1024, SocketFlags.None, ref _listenPort, ReceiveData, _listenSocket);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(textBox1.Text))
        {
            var newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            var response = Encoding.Unicode.GetBytes(textBox1.Text);
            newSocket.SendTo(response, 0, response.Length, SocketFlags.None, _testClientPort);

            this.richTextBox.AppendText($"服务器(本地): {textBox1.Text}\n");
        }
    }
}

客户端:

public partial class Client : Form
{     
    //客户端用来接收数据的socket
    private readonly Socket _listenSocket;

    private EndPoint _listenPort = new IPEndPoint(IPAddress.Parse("192.168.2.32"), 7943);
    private readonly EndPoint _serverPort = new IPEndPoint(IPAddress.Parse("192.168.2.32"), 7942);

    //保存聊天信息
    private readonly byte[] _buffer = new byte[1024];

    //保存服务器地址
    private EndPoint _serverIpPort;

    //收到的数据(字符串)
    private string _receiveData = string.Empty;

    //定义委托
    private delegate void ShowDataDelegate();

    public Client()
    {
        InitializeComponent();

        //获取服务端聊天信息
        _listenSocket = new Socket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp);
        _listenSocket.Bind(_listenPort);
        _listenSocket.BeginReceiveFrom(_buffer, 0, 1024, SocketFlags.None, ref _listenPort, new AsyncCallback(ReceiveData), _listenSocket);
    }

    private void ShowData()
    {
        if (!string.IsNullOrEmpty(_receiveData))
        {
            this.richTextBox.AppendText($"服务器({_serverIpPort}): {_receiveData}\n");
        }
    }

    private void ReceiveData(IAsyncResult ar)
    {
        // 创建ip+port
        var sender = new IPEndPoint(IPAddress.Any, 0);
        var tempRemoteEp = (EndPoint)sender;

        //获取socket
        Socket remote = (Socket)ar.AsyncState;

        //获取服务端发来的数据(服务端ip+port在第二个参数中)
        var recv = remote.EndReceiveFrom(ar, ref tempRemoteEp);

        //服务端ip+端口
        _serverIpPort = tempRemoteEp;

        //将数据流转成字符串
        _receiveData = Encoding.Unicode.GetString(_buffer, 0, recv);

        //刷新界面数据
        this.richTextBox.Invoke(new ShowDataDelegate(ShowData));
        
        if (!this.IsDisposed)
        {
            _listenSocket.BeginReceiveFrom(_buffer, 0, 1024, SocketFlags.None, ref _listenPort, new AsyncCallback(ReceiveData), _listenSocket);
        }
    }

    private void button_send_Click(object sender, EventArgs e)
    {
        SendDataToServer();
    }

    private void SendDataToServer()
    {
        if (!string.IsNullOrEmpty(this.textBox_sendInfo.Text))
        {
            //创建udp socket
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            var dataArray = Encoding.Unicode.GetBytes(this.textBox_sendInfo.Text);

            //发送至服务端
            socket.SendTo(dataArray, 0, dataArray.Length, SocketFlags.None, _serverPort);

            this.richTextBox.AppendText($"客户端(本地): {this.textBox_sendInfo.Text}\n");
        }
    }
}

剩下的界面控件,直接去工具箱拖出来改成和代码对应的name即可,或者直接到这下载icon-default.png?t=M666https://download.csdn.net/download/sudazf/86245369

2.第二个示例,使用.net 自带的 Socket 纯手工写 (Tcp协议)

同上,分别加入服务端和客户端代码:

服务端:

public partial class Server : Form
{
    //建立连接后的Socket实例
    private Socket _socket;

    //定个委托
    public delegate void ShowDataDelegate(string data);

    public Server()
    {
        InitializeComponent();

        //创建接收客户端消息的socket
        var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        listenSocket.Bind(new IPEndPoint(IPAddress.Any, 7942));
        listenSocket.Listen(10);

        Task.Run(() =>
        {
            _socket = listenSocket.Accept();
            byte[] receive = new byte[1024];
            while (true)
            {
                _socket.Receive(receive);
                var data = Encoding.Unicode.GetString(receive);
                this.richTextBox.Invoke(new ShowDataDelegate(ShowData), data);
            }
        });
    }

    private void ShowData(string data)
    {
        if (!string.IsNullOrEmpty(data))
        {
            this.richTextBox.AppendText($"客户端({_socket.RemoteEndPoint}): {data}");
            this.richTextBox.AppendText("\n");
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(textBox1.Text))
        {
            byte[] data = Encoding.Unicode.GetBytes(this.textBox1.Text);

            _socket.SendTo(data, 0, data.Length, SocketFlags.None, _socket.RemoteEndPoint);

            this.richTextBox.AppendText($"服务器(本地): {textBox1.Text}\n");
        }
    }
}

客户端:

public partial class Client : Form
{     
    //客户端用来接收数据的socket
    private readonly Socket _listenSocket;

    //服务器地址
    private readonly EndPoint _serverAddress = new IPEndPoint(IPAddress.Parse("192.168.2.32"), 7942);

    //定义委托
    private delegate void ShowDataDelegate(string data);


    public Client()
    {
        InitializeComponent();

        _listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _listenSocket.Connect(_serverAddress);

        Task.Run(() =>
        {
            byte[] receive = new byte[1024];
            while (true)
            {
                _listenSocket.Receive(receive);
                var data = Encoding.Unicode.GetString(receive);
                this.richTextBox.Invoke(new ShowDataDelegate(ShowData), data);
            }
        });
    }

    private void ShowData(string data)
    {
        if (!string.IsNullOrEmpty(data))
        {
            this.richTextBox.AppendText($"服务器({_listenSocket.RemoteEndPoint}): {data}");
            this.richTextBox.AppendText("\n");
        }
    }

    private void button_send_Click(object sender, EventArgs e)
    {
        SendDataToServer();
    }

    private void SendDataToServer()
    {
        if (!string.IsNullOrEmpty(this.textBox_sendInfo.Text))
        {
            var dataArray = Encoding.Unicode.GetBytes(this.textBox_sendInfo.Text);
            _listenSocket.SendTo(dataArray, 0, dataArray.Length, SocketFlags.None, _serverAddress);

            this.richTextBox.AppendText($"客户端(本地): {this.textBox_sendInfo.Text}\n");
        }
    }
}

或者直接到这里下载icon-default.png?t=M666https://download.csdn.net/download/sudazf/86245419

3.第三个示例,直接使用WebSocket【推荐使用】

使用WebSocket方法有很多种,这里记录几种:

为了简便示例,服务端就使用 Fleck 

开源地址在 GitHub - statianzo/Fleck: C# Websocket Implementation

服务端代码:

static void Main(string[] args)
{
	FleckLog.Level = LogLevel.Debug;
	var allSockets = new List<IWebSocketConnection>();
	var server = new WebSocketServer("ws://0.0.0.0:8181");
	server.Start(socket =>
	{
		socket.OnOpen = () =>
		{
			Console.WriteLine("Open!");
			allSockets.Add(socket);
		};
		socket.OnClose = () =>
		{
			Console.WriteLine("Close!");
			allSockets.Remove(socket);
		};
		socket.OnMessage = message =>
		{
			Console.WriteLine(message);
			allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
		};
	});

	var input = Console.ReadLine();
	while (input != "exit")
	{
		foreach (var socket in allSockets.ToList())
		{
			socket.Send(input);
		}
		input = Console.ReadLine();
	}
}

客户端就有很多种了:

比如直接用Chrome console终端:

或者直接前端javascript

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>websocket client</title>
    <script type="text/javascript">
        var start = function () {
            var inc = document.getElementById('incomming');
            var wsImpl = window.WebSocket || window.MozWebSocket;
            var form = document.getElementById('sendForm');
            var input = document.getElementById('sendText');
            
            inc.innerHTML += "connecting to server ..<br/>";

            // create a new websocket and connect
            window.ws = new wsImpl('ws://localhost:8181/');

            // when data is comming from the server, this metod is called
            ws.onmessage = function (evt) {
                inc.innerHTML += evt.data + '<br/>';
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                inc.innerHTML += '.. connection open<br/>';
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                inc.innerHTML += '.. connection closed<br/>';
            }
            
			form.addEventListener('submit', function(e){
				e.preventDefault();
				var val = input.value;
				ws.send(val);
				input.value = "";
			});
            
        }
        window.onload = start;
    </script>
</head>
<body>
	<form id="sendForm">
		<input id="sendText" placeholder="Text to send" />
	</form>
    <pre id="incomming"></pre>
</body>
</html>

再或者使用微软自带的 ClientWebSocket

public partial class MainWindow : Window
{
	private ClientWebSocket _webSocket;
	private CancellationToken _cancellation;
	public MainWindow()
	{
		InitializeComponent();
		Init();
	}

	private async Task<int> Init()
	{
		_webSocket = new ClientWebSocket();
		_cancellation = new CancellationToken();
		await _webSocket.ConnectAsync(new Uri("ws://127.0.0.1:8181/"), _cancellation);
		return 1;
	}

	private async void Button_Click(object sender, RoutedEventArgs e)
	{
		var send = System.Text.Encoding.UTF8.GetBytes("Hello,女神在吗?");
		await _webSocket.SendAsync(new ArraySegment<byte>(send), WebSocketMessageType.Text, true, _cancellation);
   
		byte[] rec = new byte[1024];
		await _webSocket.ReceiveAsync(new ArraySegment<byte>(rec), _cancellation);
		string str = System.Text.Encoding.UTF8.GetString(rec);
		MessageBox.Show(str);
	}
}

个人觉推荐还是用下面的 WebSocket4Net,简单好用

private static WebSocket _websocketClient;
static void Main(string[] args)
{
	try
	{
		_websocketClient = new WebSocket("ws://192.168.1.173:8181/");
		_websocketClient.Opened += Websocket_Opened;
		_websocketClient.Closed += WebsocketClient_Closed;
		_websocketClient.Error += WebsocketClient_Error;
		_websocketClient.Open();

		Console.Read();
	}
	catch (Exception e)
	{
		Console.WriteLine(e);		
	}
}

private static void Websocket_Opened(object sender, EventArgs e)
{
	Console.WriteLine("Opened");
	_websocketClient.Send("Hello world!");
}

private static void WebsocketClient_Closed(object sender, EventArgs e)
{
	Console.WriteLine("Closed");
}

private static void WebsocketClient_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
{
	Console.WriteLine($"Error: {e.Exception.Message}");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值