Windows實現Socket通訊示例

一個服務器連多個客戶端,支持服務器往客戶端推送消息,也支持客戶端往服務器發送消息。先看效果:

源碼下載:https://download.csdn.net/download/a497785609/12263264

服務器端代碼:(僅列出主要代碼,完整代碼請下載資源源碼)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Server
{
    public partial class Server : Form
    {
        private static Socket _server;
        private static readonly byte[] Buffer = new byte[1024];

        private readonly Dictionary<string, Socket> _sockets = new Dictionary<string, Socket>();
        private readonly Dictionary<string, Thread> _threads = new Dictionary<string, Thread>();

        public Server()
        {
            InitializeComponent();
        }

        public void UpdateUI(Action action)
        {
            if (InvokeRequired)
                Invoke(action);
            else
                action();
        }

        public void Log(string msg)
        {
            UpdateUI(() =>
            {
                txtLog.Select(txtLog.TextLength, 0);
                txtLog.ScrollToCaret();
                txtLog.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + msg + Environment.NewLine);
            });
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            var ip = IPAddress.Parse(txtServer.Text.Trim());
            _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _server.Bind(new IPEndPoint(ip, Convert.ToInt32(txtPort.Text.Trim())));
            _server.Listen(10); //設定最多10個排隊連接請求   
            Log("服務器已開始偵聽..." + _server.LocalEndPoint);
            var thread = new Thread(ListenClient);
            thread.Start();
        }

        private void ListenClient()
        {
            while (true)
            {
                var socket = _server.Accept();
                Log(string.Format("客戶端 [{0}] 連接成功!", socket.RemoteEndPoint));
                var thread = new Thread(ReceiveMessage);
                thread.Start(socket);
                if (!_sockets.ContainsKey(socket.RemoteEndPoint.ToString()))
                {
                    _sockets.Add(socket.RemoteEndPoint.ToString(), socket);
                    ShowClient();
                }
                if (!_threads.ContainsKey(socket.RemoteEndPoint.ToString()))
                {
                    _threads.Add(socket.RemoteEndPoint.ToString(), thread);
                }
            }
        }

        private void ReceiveMessage(object clientSocket)
        {
            var socket = (Socket)clientSocket;
            while (true)
                try
                {
                    var count = socket.Receive(Buffer);
                    var txt = Encoding.UTF8.GetString(Buffer, 0, count);
                    if (txt == "off" || txt == "")
                    {
                        if (_sockets.ContainsKey(socket.RemoteEndPoint.ToString()))
                        {
                            _sockets.Remove(socket.RemoteEndPoint.ToString());
                            ShowClient();
                            Log(string.Format("接收客戶端 [{0}] 已斷開", socket.RemoteEndPoint));
                        }
                        if (_threads.ContainsKey(socket.RemoteEndPoint.ToString()))
                        {
                            _threads[socket.RemoteEndPoint.ToString()].Abort();
                        }
                    }
                    else
                    {
                        Log(string.Format("接收客戶端 [{0}] 消息 [{1}]", socket.RemoteEndPoint, txt));
                    }
                }
                catch (Exception ex)
                {
                    if (socket != null && socket.Connected)
                    {
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Close();
                    }

                    break;
                }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            var msg = txtMsg.Text.Trim();
            try
            {
                //向所有連上的socket發送消息
                foreach (var pair in _sockets)
                    if (pair.Value.Connected)
                    {
                        pair.Value.Send(Encoding.UTF8.GetBytes(msg));
                        Log("向客戶端發送消息:" + msg);
                    }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Server_FormClosing(object sender, FormClosingEventArgs e)
        {
            foreach (var pair in _sockets)
                if (pair.Value != null)
                {
                    if (pair.Value.Connected && pair.Value.Available > 0)
                    {
                        pair.Value.Send(Encoding.UTF8.GetBytes("off"));
                        pair.Value.Shutdown(SocketShutdown.Both);
                        pair.Value.Disconnect(false);
                    }

                    pair.Value.Close();
                    pair.Value.Dispose();
                }

            var tt = Process.GetProcessById(Process.GetCurrentProcess().Id);
            tt.Kill();
        }

        public void ShowClient()
        {
            UpdateUI(() =>
            {
                listBox.Items.Clear();
                foreach (var pair in _sockets) listBox.Items.Add(pair.Key);
            });
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtLog.Text = "";
        }
    }
}

客戶端端代碼:(僅列出主要代碼,完整代碼請下載資源源碼)

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Client
{
    public partial class Client : Form
    {
        private static readonly byte[] Buffer = new byte[1024];
        private bool _isContinue = true;

        private Thread _thread;

        private Socket socket;

        public Client()
        {
            InitializeComponent();
        }

        public void UpdateUI(Action action)
        {
            if (InvokeRequired)
                Invoke(action);
            else
                action();
        }

        public void Log(string msg)
        {
            UpdateUI(() =>
            {
                txtLog.Select(txtLog.TextLength, 0);
                txtLog.ScrollToCaret();
                txtLog.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + msg + Environment.NewLine);
            });
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (socket != null && socket.IsBound)
            {
                Log("已連接,請勿重複連接");
                return; 
            }

            var ip = IPAddress.Parse(txtServer.Text.Trim());
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket.Connect(new IPEndPoint(ip, Convert.ToInt32(txtPort.Text.Trim())));
                Log("連接服務器成功");
                socket.Send(Encoding.UTF8.GetBytes(txtName.Text.Trim() + "|Login"));

                //新開線程,偵聽服務器端返回信息
                _thread = new Thread(ReceiveListener);
                _thread.Start();
            }
            catch
            {
                Log("連接服務器失敗,請檢查服務器是否已啓動!");
            }
        }

        private void ReceiveListener()
        {
            try
            {
                while (_isContinue)
                    if (socket != null && socket.Connected && socket.Blocking)
                    {
                        var count = socket.Receive(Buffer);
                        var txt = Encoding.UTF8.GetString(Buffer, 0, count);
                        if (txt == "off")
                        {
                            _isContinue = false;
                            Log("服務器已關閉");
                        }
                        else
                        {
                            Log(string.Format("接收到服務器 [{0}] 消息 [{1}]", socket.RemoteEndPoint, txt));
                        }
                    }
                    else
                    {
                        _isContinue = false;
                        Log("服務器已關閉");
                        _thread.Abort();
                    }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                var msg = txtMsg.Text.Trim();
                if (socket == null)
                {
                    Log("抱歉,請先連接服務器!");
                    return;
                }
                if (socket.IsBound && socket.Connected)
                {
                    socket.Send(Encoding.UTF8.GetBytes(txtName.Text.Trim() + "|" + msg));
                    Log("向服務器發送消息:" + msg);
                }
                else
                {
                    Log("抱歉,Socket已斷開!");
                    return;
                }
            }
            catch (Exception ex)
            {
                Log(ex.Message);
            }
        }

        private void Client_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (socket != null)
            {
                if (socket.Connected)
                {
                    socket.Send(Encoding.UTF8.GetBytes("off"));
                    socket.Shutdown(SocketShutdown.Both);
                }
                //socket.Disconnect(false);
                socket.Close();
                socket.Dispose();
            }

            var tt = Process.GetProcessById(Process.GetCurrentProcess().Id);
            tt.Kill();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtLog.Text = "";
        }
    }
}

源碼下載:https://download.csdn.net/download/a497785609/12263264

===============================補充====================================

配合Android手機客戶端,可以實現手機與服務器間的socket連接,可以發揮的功能就很多了,比如:

1.手機發送命令,由服務器中轉,遠程控制電腦。

2.服務器端往手機推送消息等。

Android客戶端代碼:(僅供參考)

package com.rc114.ui;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.InputType;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.rc114.R;
import com.rc114.updater.Notifyer;

import org.w3c.dom.Text;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MySocket extends Activity {
    Socket socket;
    EditText txtMsg;
    EditText txtLog;
    public final int NEWMESSAGE = 1;
    public final int Exception = 2;
    public final int Receive = 3;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//隱藏標題欄
        setContentView(R.layout.layout_socket);

        txtMsg = findViewById(R.id.txtMsg);
        txtLog = findViewById(R.id.txtLog);

        //連接測試
        Button btnConn = findViewById(R.id.btnConn);
        btnConn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            if (socket != null && !socket.isClosed()) {
                                Message message = new Message();
                                message.what = NEWMESSAGE;
                                message.obj = "已連接,請勿重複連接";
                                handler.sendMessage(message);
                            } else {
                                String host = "120.78.204.206";
                                int port = 2020;
                                socket = new Socket(host, port);
                                if (socket.isConnected()) {
                                    Message message = new Message();
                                    message.what = NEWMESSAGE;
                                    message.obj = "連接成功";
                                    handler.sendMessage(message);

                                    Runnable handler = new LinstenHandler(socket);
                                    Thread thread = new Thread(handler);
                                    thread.start();
                                }
                            }
                        } catch (IOException e) {
                            Message message = new Message();
                            message.what = Exception;
                            message.obj = e.getMessage();
                            handler.sendMessage(message);
                            e.printStackTrace();
                        }
                    }
                }).start();

            }
        });

        //發送信息
        Button btnSend = findViewById(R.id.btnSend);
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    public void run() {
                        try {
                            String txt = txtMsg.getText().toString();
                            if (socket.isConnected()) {
                                socket.getOutputStream().write(txt.getBytes("UTF-8"));

                                Message message = new Message();
                                message.what = NEWMESSAGE;
                                message.obj = "發送:" + txt;
                                handler.sendMessage(message);
                            }
                        } catch (IOException e) {
                            Message message = new Message();
                            message.what = Exception;
                            message.obj = e.getMessage();
                            handler.sendMessage(message);
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        });
        //清除記錄
        Button btnClear = findViewById(R.id.btnClear);
        btnClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                txtLog.setText("");
            }
        });

        //斷開連接
        Button btnClose = findViewById(R.id.btnClose);
        btnClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    public void run() {
                        try {
                            if (socket != null) {
                                socket.shutdownInput();
                                socket.shutdownOutput();
                                socket.close();
                            }
                            Message message = new Message();
                            message.what = NEWMESSAGE;
                            message.obj = "斷開連接";
                            handler.sendMessage(message);

                        } catch (IOException e) {
                            Message message = new Message();
                            message.what = Exception;
                            message.obj = e.getMessage();
                            handler.sendMessage(message);
                            e.printStackTrace();
                        }
                    }
                }.start();

            }
        });
    }

    class LinstenHandler implements Runnable {
        private Socket socket;

        public LinstenHandler(Socket i) {
            socket = i;
        }

        public void run() {
            try {
                while (true)
                    if (socket != null && socket.isConnected() && socket.isBound()) {
                        // 讀取數據
                        InputStream inputStream = socket.getInputStream();
                        byte[] bytes = new byte[1024];
                        int len;
                        while ((len = inputStream.read(bytes)) != -1) {
                            String txt = (new String(bytes, 0, len, "UTF-8"));
                            Message message = new Message();
                            message.what = Receive;
                            message.obj = "接收:" + txt;
                            handler.sendMessage(message);
                        }
                    }
            } catch (IOException e) {
                Message message = new Message();
                message.what = Exception;
                message.obj = e.getMessage();
                handler.sendMessage(message);
                e.printStackTrace();
            }
        }
    }

    final Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case Exception:
                case NEWMESSAGE: {
                    String s = (txtLog.getText() + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(new Date()) + (String) msg.obj + "\n");
                    txtLog.setText(s);
                    txtLog.setSelection(s.length(), s.length());
                }
                break;
                case Receive: {
                    String s = (txtLog.getText() + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(new Date()) + (String) msg.obj + "\n");
                    txtLog.setText(s);
                    txtLog.setSelection(s.length(), s.length());
                    new Notifyer().notifiy("收到通知", (String) msg.obj, null, true);
                }
                break;
                default:
                    break;
            }
        }
    };


}

對應視圖:layout_socket.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Socket測試"
        android:textColor="@android:color/black"
        android:textSize="16dp"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/txtMsg"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:layout_margin="3dp"
        android:background="@drawable/edit_text"
        android:gravity="top"
        android:padding="3dp"
        android:singleLine="false"
        android:text="測試信息"
        android:textSize="12dp" />

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnConn"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginRight="5dp"
            android:background="@drawable/button_default"
            android:text="連接"
            android:textColor="#ffffff"
            android:textSize="12dp" />

        <Button
            android:id="@+id/btnSend"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginRight="5dp"
            android:background="@drawable/button_default"
            android:text="發送"
            android:textColor="#ffffff"
            android:textSize="12dp" />

        <Button
            android:id="@+id/btnClose"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginRight="5dp"
            android:background="@drawable/button_default"
            android:text="斷開"
            android:textColor="#ffffff"
            android:textSize="12dp" />

        <Button
            android:id="@+id/btnClear"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginRight="5dp"
            android:background="@drawable/button_default"
            android:text="清除"
            android:textColor="#ffffff"
            android:textSize="12dp" />
    </LinearLayout>


    <EditText
        android:id="@+id/txtLog"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="3dp"
        android:background="@drawable/edit_text"
        android:gravity="top"
        android:singleLine="false"
        android:layout_weight="1"
        android:textSize="12dp" />
</LinearLayout>

效果圖:

源碼下載:https://download.csdn.net/download/a497785609/12263264 (僅Windows程序,不含Android客戶端)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章