1. 程式人生 > >C#:簡單的Socket非同步通訊服務

C#:簡單的Socket非同步通訊服務

Socket

請參考此連結來獲取對於Socket的認識:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.aspx

目標

1、服務端接收到來自客戶端的訊息

2、服務端間歇性地向客戶端傳送訊息

3、服務端主動向客戶端傳送訊息

思路

通過對Socket的學習後,可以知道:

1、Socket分為面向連線協議(如TCP)和無連線協議(如UDP)

2、Socket通訊分為同步操作模式和非同步操作模式,同步模式在建立連線之前/收到訊息之前會阻塞當前程序,非同步模式不會阻塞當前程序

綜合以上兩點,考慮到體驗,當然是選擇非同步Socket啦,另外,這裡使用的是面向連線的協議,那麼實現思路大致如下:

1、建立Socket物件

2、繫結IP和埠

3、偵聽連線

4、開始一個非同步操作來接收一個接入的連線請求

5、處理接入的請求

6、向客戶端傳送訊息

程式碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.IO;
using Microsoft.Win32;
using System.Threading;
using System.Net;
using System.Net.Sockets;


namespace TSNotifier
{
    public partial class TSNotifier : ServiceBase
    {
        Socket socket;
        public TSNotifier()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 服務啟動
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            //Debugger.Launch();//啟動除錯,生產環境刪掉
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(new IPEndPoint(IPAddress.Any, 4530));//偵聽來自任意IP的連線請求
            socket.Listen(500);
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
        }
        /// <summary>
        /// 服務停止
        /// </summary>
        protected override void OnStop()
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            catch (Exception ex)
            {


            }
        }


        public static void ClientAccepted(IAsyncResult ar)
        {
            var socket = ar.AsyncState as Socket;
            var client = socket.EndAccept(ar);
            string clientIp = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address.ToString();
            string clientPort = ((System.Net.IPEndPoint)client.RemoteEndPoint).Port.ToString();
            client.Send(Encoding.Unicode.GetBytes("Hi " + clientIp + ":" + clientPort + ", I accept you request at " + DateTime.Now.ToString()));


            //每隔兩秒鐘給客戶端發一個訊息
            var timer = new System.Timers.Timer();
            timer.Interval = 2000;
            timer.Enabled = true;
            timer.Elapsed += (o, a) =>
            {
                //檢測客戶端Socket的狀態
                if (client.Connected)
                {
                    try
                    {
                        client.Send(Encoding.Unicode.GetBytes("Server online."));
                    }
                    catch (SocketException ex)
                    {


                    }
                }
                else
                {
                    timer.Stop();
                    timer.Enabled = false;
                }
            };
            timer.Start();
            //接收客戶端的訊息
            try
            {
                client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client);
            }
            catch (Exception ex)
            {


            }
            //準備接受下一個客戶端請求
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
        }


        static byte[] buffer = new byte[1024];
        public static void ReceiveMessage(IAsyncResult ar)
        {
            var socket = ar.AsyncState as Socket;
            string clientIp = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString();
            string clientPort = ((IPEndPoint)socket.RemoteEndPoint).Port.ToString();
            try
            {
                var length = socket.EndReceive(ar);
                var message = Encoding.Unicode.GetString(buffer, 0, length);
                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
            }
            catch (Exception ex)
            {


            }
        }
    }
}

客戶端的實現請參考:http://www.rexcao.net/archives/161