代码改变世界

常用的 WinForm 程序

2011-11-25 20:49  音乐让我说  阅读(309)  评论(0)    收藏  举报

 

1. 利用 Windows Forms 创建自动登录程序

 

1. 新建一个 Windows Forms 应用程序。

2. 拖一个 Panel,再向该 Panel 中拖一个 Label、TextBox、Button。设置 Panel 的 Dock 属性为 Top,其中 Top 就是固定在窗口的头部。设置 TextBox 的 Text = http://passport.cnblogs.com/login.aspx

3. 再拖一个 Panel,再向该 Panel 中拖一个 WebBrowser,设置 Panel 和 WebBrowser 的 Dock 属性为 Fill,其中 Fill 就是全屏。再设置 WebBrowser 的 Url = "http://www.cnblogs.com/"。

4. 在后台代码中编写下面的代码:

private void button1_Click(object sender, EventArgs e)
{
    string sUrl = this.txtUrl.Text.Trim();

    if (sUrl.Length > 0)
    {
        webBrowser1.Navigate(sUrl);
    }
}

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url.ToString().ToLower().IndexOf("login.aspx") == -1)
    {
        return;
    }
    HtmlElement clickBtn = null;
    HtmlDocument doc = webBrowser1.Document;
    for (int i = 0; i < doc.All.Count; i++)
    {
        if (!doc.All[i].TagName.ToUpper().Equals("INPUT"))
        {
            continue;
        }
        switch (doc.All[i].Name)
        {
            case "tbUserName":
                doc.All[i].InnerText = "xxxxxx";  // 用户名
                break;
            case "tbPassword":
                doc.All[i].InnerText = "123456";      // 密码
                break;
            case "btnLogin":
                clickBtn = doc.All[i];
                break;
        }
    }
    if (clickBtn != null)
    {
        clickBtn.InvokeMember("click"); // 点击“登录”按钮
    }
}

 

5. 点击“登录”按钮运行。

附录:Partial 类中的代码如下:

partial class AutoLogin
{
    /// <summary>
    /// 必需的设计器变量。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows 窗体设计器生成的代码

    /// <summary>
    /// 设计器支持所需的方法 - 不要
    /// 使用代码编辑器修改此方法的内容。
    /// </summary>
    private void InitializeComponent()
    {
        this.lblUrl = new System.Windows.Forms.Label();
        this.txtUrl = new System.Windows.Forms.TextBox();
        this.button1 = new System.Windows.Forms.Button();
        this.webBrowser1 = new System.Windows.Forms.WebBrowser();
        this.panel1 = new System.Windows.Forms.Panel();
        this.panel2 = new System.Windows.Forms.Panel();
        this.panel1.SuspendLayout();
        this.panel2.SuspendLayout();
        this.SuspendLayout();
        // 
        // lblUrl
        // 
        this.lblUrl.AutoSize = true;
        this.lblUrl.Location = new System.Drawing.Point(3, 31);
        this.lblUrl.Name = "lblUrl";
        this.lblUrl.Size = new System.Drawing.Size(77, 12);
        this.lblUrl.TabIndex = 0;
        this.lblUrl.Text = "请输入地址:";
        // 
        // txtUrl
        // 
        this.txtUrl.Location = new System.Drawing.Point(86, 22);
        this.txtUrl.Name = "txtUrl";
        this.txtUrl.Size = new System.Drawing.Size(342, 21);
        this.txtUrl.TabIndex = 1;
        this.txtUrl.Text = "http://passport.cnblogs.com/login.aspx";
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(446, 20);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(75, 23);
        this.button1.TabIndex = 2;
        this.button1.Text = "登录";
        this.button1.UseVisualStyleBackColor = true;
        this.button1.Click += new System.EventHandler(this.button1_Click);
        // 
        // webBrowser1
        // 
        this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
        this.webBrowser1.Location = new System.Drawing.Point(0, 0);
        this.webBrowser1.Margin = new System.Windows.Forms.Padding(0);
        this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20);
        this.webBrowser1.Name = "webBrowser1";
        this.webBrowser1.Size = new System.Drawing.Size(600, 321);
        this.webBrowser1.TabIndex = 3;
        this.webBrowser1.Url = new System.Uri("http://www.cnblogs.com/", System.UriKind.Absolute);
        this.webBrowser1.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser1_DocumentCompleted);
        // 
        // panel1
        // 
        this.panel1.Controls.Add(this.lblUrl);
        this.panel1.Controls.Add(this.txtUrl);
        this.panel1.Controls.Add(this.button1);
        this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
        this.panel1.Location = new System.Drawing.Point(0, 0);
        this.panel1.Name = "panel1";
        this.panel1.Size = new System.Drawing.Size(600, 67);
        this.panel1.TabIndex = 4;
        // 
        // panel2
        // 
        this.panel2.Controls.Add(this.webBrowser1);
        this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
        this.panel2.Location = new System.Drawing.Point(0, 67);
        this.panel2.Name = "panel2";
        this.panel2.Size = new System.Drawing.Size(600, 321);
        this.panel2.TabIndex = 5;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.AutoSize = true;
        this.ClientSize = new System.Drawing.Size(600, 388);
        this.Controls.Add(this.panel2);
        this.Controls.Add(this.panel1);
        this.Name = "Form1";
        this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
        this.Text = "自动登录程序";
        this.panel1.ResumeLayout(false);
        this.panel1.PerformLayout();
        this.panel2.ResumeLayout(false);
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Label lblUrl;
    private System.Windows.Forms.TextBox txtUrl;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.WebBrowser webBrowser1;
    private System.Windows.Forms.Panel panel1;
    private System.Windows.Forms.Panel panel2;
}

 

2. TCP 客户端帮助类

1.

using System;

namespace Utility.Comm
{
  public interface IComm
  {
    event Action Connected;
    event Action Disconnected;
    event Action<byte[]> Received;

    void Start();
    void Stop();
    bool IsStarted { get; }
    bool IsConnected { get; }

    void Send(byte[] data);
  }
}

 

2.  

using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace Utility.Comm.Tcp
{
  public class TcpClient : IComm
  {
    public event Action Connected;
    public event Action Disconnected;
    public event Action<byte[]> Received;

    private readonly object sync = new object();

    private Socket socket;
    private bool isStarted;
    private IPEndPoint _endPoint;

    private bool stop;

    private const int ReceiveBufferSize = 1024;
    private readonly byte[] receiveBuffer = new byte[ReceiveBufferSize];

    public string ServerAddress { get; private set; }

    public int ServerPort { get; private set; }

    public TcpClient(string serverAddress, int serverPort)
    {
      ServerAddress = serverAddress;
      ServerPort = serverPort;
    }

    public void Start()
    {
      if (IsStarted)
        return;

      lock (sync) stop = false;

      IsStarted = true;

      Dns.BeginGetHostAddresses(ServerAddress, GetHostAddressesCallback, null);
    }

    public virtual void Stop()
    {
      if (!IsStarted)
        return;

      lock (sync)
      {
        stop = true;
        _endPoint = null;
        if (socket != null)
        {
          if (socket.Connected)
          {
            RaiseDisconnected();
          }
          socket.Close();
          socket = null;
        }
      }

      IsStarted = false;
    }

    public bool IsStarted
    {
      get { return isStarted; }
      protected set
      {
        if (isStarted.Equals(value))
        {
          return;
        }
        isStarted = value;

        var logger = NLog.LogManager.GetCurrentClassLogger();
        if (isStarted)
          logger.Info("{0} Started : {1}:{2}", GetType().Name, ServerAddress, ServerPort);
        else
          logger.Info("{0} Stopped", GetType().Name);
      }
    }

    public bool IsConnected
    {
      get { lock(sync) return socket != null && socket.Connected; }
    }

    public void Send(byte[] message)
    {
      try
      {
        lock (sync)
        {
          if (stop || socket == null || !socket.Connected)
          {
            return;
          }
          socket.Send(message);
        }
      }
      catch (SocketException ex)
      {
        if (ex.ErrorCode == 10054)
        {
          // 10054 == An existing connection was forcibly closed by the remote host
          // Expected when a remote client disconnects.
          ServerDisconnected();
          return;
        }

        NLog.LogManager.GetCurrentClassLogger()
            .ErrorException(string.Format("Send : SocketException : {0} : {1}", ex.ErrorCode, ex.Message), ex);
      }
      catch (Exception ex)
      {
        NLog.LogManager.GetCurrentClassLogger()
            .ErrorException(string.Format("Send : {0} : {1}", ex.GetType(), ex.Message), ex);
      }
    }

    private void GetHostAddressesCallback(IAsyncResult ar)
    {
      try
      {
        lock (sync) if (stop) return;

        var ipAddresses = Dns.EndGetHostAddresses(ar);
        var serverIpAddress = ipAddresses.FirstOrDefault(ipAddress => ipAddress.AddressFamily == AddressFamily.InterNetwork);

        if(serverIpAddress == null)
          throw new Exception(string.Format("Could not resolve server address '{0}'", ServerAddress));

        _endPoint = new IPEndPoint(serverIpAddress, ServerPort);

        lock (sync)
        {
          socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          socket.BeginConnect(_endPoint, ConnectCallback, null);
        }

      }
      catch (Exception ex)
      {
        NLog.LogManager.GetCurrentClassLogger().WarnException(string.Format("GetHostAddressesCallback : {0} : {1}", ex.GetType(), ex.Message), ex);
        Thread.Sleep(2000);

        lock (sync) if (stop) return;
        Dns.BeginGetHostAddresses(ServerAddress, GetHostAddressesCallback, null);
      }
    }


    private void ConnectCallback(IAsyncResult ar)
    {
      try
      {
        lock (sync)
        {
          if (stop) return;

          socket.EndConnect(ar);

          RaiseConnected();

          SocketError receiveError;
          socket.BeginReceive(receiveBuffer, 0, ReceiveBufferSize, SocketFlags.None, out receiveError, ReceiveCallback, null);
        }
      }
      catch (SocketException ex)
      {
        NLog.LogManager.GetCurrentClassLogger().WarnException(string.Format("ConnectCallback : SocketException : {0} : {1}", ex.ErrorCode, ex.Message),
                             ex);
        Thread.Sleep(2000);
        lock (sync)
        {
          if (stop) return;
          socket.BeginConnect(_endPoint, ConnectCallback, null);
        }
      }
      catch (Exception ex)
      {
        NLog.LogManager.GetCurrentClassLogger().WarnException(string.Format("ConnectCallback : {0} : {1}", ex.GetType(), ex.Message), ex);
        Thread.Sleep(2000);
        lock (sync)
        {
          if (stop) return;
          socket.BeginConnect(_endPoint, ConnectCallback, ar.AsyncState);
        }
      }
    }


    private void ReceiveCallback(IAsyncResult ar)
    {
      var logger = NLog.LogManager.GetCurrentClassLogger();
      try
      {
        int received;
        lock (sync)
        {
          if (stop) return;

          received = socket.EndReceive(ar);
          if (received == 0)
          {
            if (stop) return;
            ServerDisconnected();
          }
        }

        var buffer = new byte[received];
        Buffer.BlockCopy(receiveBuffer, 0, buffer, 0, received);

        RaiseReceived(buffer);

        lock (sync)
        {
          if (stop) return;
          SocketError receiveError;
          socket.BeginReceive(receiveBuffer, 0, ReceiveBufferSize, SocketFlags.None, out receiveError, ReceiveCallback, null);
        }
      }
      catch (SocketException ex)
      {

        if (ex.ErrorCode == 10054 || ex.ErrorCode == 10060)
        {
          // 10054 == An existing connection was forcibly closed by the remote host
          // 10060 == An established connection failed because connected host has failed to respond
          // Expected when a remote client disconnects.
          ServerDisconnected();
          return;
        }

        logger.ErrorException(string.Format("ReceiveCallback : SocketException : {0} : {1}", ex.ErrorCode, ex.Message),
                              ex);

        lock (sync) if (stop) return;

      }
      catch (Exception ex)
      {
        lock (sync) if (stop) return;
        logger.ErrorException(string.Format("ReceiveCallback : {0} : {1}", ex.GetType(), ex.Message), ex);
      }
    }

    private void ServerDisconnected()
    {
      lock (sync)
      {
        if (stop) return;
        if (socket.Connected)
        {
          socket.Disconnect(true);
        }
        RaiseDisconnected();
        socket.BeginConnect(_endPoint, ConnectCallback, null);
      }
    }

    private void RaiseConnected()
    {
      //NLog.LogManager.GetCurrentClassLogger().Info("{0} Connected : {1}:{2}", GetType().Name, ServerAddress, ServerPort);
     
      if (Connected != null)
      {
        Connected();
      }
    }

    private void RaiseDisconnected()
    {
      //NLog.LogManager.GetCurrentClassLogger().Info("{0} Disconnected : {1}:{2}", GetType().Name, ServerAddress, ServerPort);

      if (Disconnected != null)
      {
        Disconnected();
      }
    }

    private void RaiseReceived(byte[] data)
    {
      //NLog.LogManager.GetCurrentClassLogger().Info("{0} Received : {1}:{2}", GetType().Name, ServerAddress, ServerPort);

      if (Received != null)
      {
        Received(data);
      }
      
    }
  }
}

 

3. TCPHelpers

服务端:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace ConnectionServer
{
    class Program
    {
        /// <summary>
        /// This lock is used for console output to avoid several clients writing at the same time.
        /// </summary>
        private static object serverLock = new object();
        /// <summary>
        /// Enable/disable console output
        /// </summary>
        private static bool showText = true;

        /// <summary>
        /// Server listen port
        /// </summary>
        private static int port;
        /// <summary>
        /// Server listen socket
        /// </summary>
        private static Socket serverSocket;

        /// <summary>
        /// Client socket and it's receive buffer
        /// </summary>
        private class ConnectionInfo
        {
            public Socket Socket;
            public byte[] Buffer;
        }

        private static List<ConnectionInfo> connections =
            new List<ConnectionInfo>();

        /// <summary>
        /// Initializes server socket which will listen to new connections
        /// </summary>
        private static void SetupServerSocket()
        {
            IPEndPoint myEndpoint = new IPEndPoint(
                IPAddress.Any, port);

            // Create the socket, bind it, and start listening
            serverSocket = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Blocking = false;

            serverSocket.Bind(myEndpoint);
            serverSocket.Listen((int)SocketOptionName.MaxConnections);
        }

        public static void Start()
        {
            Console.Write("Starting TCP server... ");
            try
            {
                SetupServerSocket();

                // you can accept multiple incomming connections at single time
                for (int i = 0; i < 10; i++)
                    serverSocket.BeginAccept(
                        new AsyncCallback(AcceptCallback), serverSocket);
            }
            catch (Exception e)
            {
                Console.WriteLine("Fail.");
                Console.WriteLine(e);
            }
            Console.WriteLine("Done. Listening.");
        }

        /// <summary>
        /// On accept, this callback is called from unknown system thread.
        /// </summary>
        /// <param name="result"></param>
        private static void AcceptCallback(IAsyncResult result)
        {
            Console.WriteLine("Accept!");
            // create new connection info to store new connection information (in this case just socket/buffer)
            ConnectionInfo connection = new ConnectionInfo();
            try
            {
                // Finish Accept
                Socket s = (Socket)result.AsyncState;
                connection.Socket = s.EndAccept(result);
                connection.Socket.Blocking = false;
                connection.Buffer = new byte[255];
                lock (connections) connections.Add(connection);

                Console.WriteLine("New connection from " + s);

                // Start Receive
                connection.Socket.BeginReceive(connection.Buffer, 0,
                    connection.Buffer.Length, SocketFlags.None,
                    new AsyncCallback(ReceiveCallback), connection);

                // Start new Accept, accept other connections
                serverSocket.BeginAccept(new AsyncCallback(AcceptCallback),
                    result.AsyncState);
            }
            catch (SocketException exc)
            {
                CloseConnection(connection);
                Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                CloseConnection(connection);
                Console.WriteLine("Exception: " + exc);
            }
        }

        /// <summary>
        /// On receive, this callback is called from unknown system thread.
        /// </summary>
        /// <param name="result"></param>
        private static void ReceiveCallback(IAsyncResult result)
        {
            ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
            try
            {
                int bytesRead = connection.Socket.EndReceive(result);
                if (0 != bytesRead)
                {
                    // note that this "serverLock" is just for outputing to console.
                    // otherwise no locks would be needed if this method did its work
                    // in isolated way
                    lock (serverLock)
                    {
                        if (showText)
                        {
                            string text = Encoding.UTF8.GetString(connection.Buffer, 0, bytesRead);
                            Console.Write(text);
                        }
                    }
                    // if we needed send simple response to the same socket, this would suffice:
                    // connection.Socket.Send(connection.Buffer, bytesRead, SocketFlags.None);

                    // however, this code sends the same received data to all other connected clients
                    // so we protect connections wile we are iterating over them
                    // to avoid any other thread removing/adding sockets while iteration
                    // is in progress
                    lock (connections)
                    {
                        foreach (ConnectionInfo conn in connections)
                        {
                            if (connection != conn)
                            {
                                conn.Socket.Send(connection.Buffer, bytesRead,
                                    SocketFlags.None);
                            }
                        }
                    }

                    // begin receive additional data
                    connection.Socket.BeginReceive(connection.Buffer, 0,
                        connection.Buffer.Length, SocketFlags.None,
                        new AsyncCallback(ReceiveCallback), connection);
                }
                else CloseConnection(connection);
            }
            catch (SocketException)
            {
                CloseConnection(connection);
            }
            catch (Exception)
            {
                CloseConnection(connection);
            }
        }

        private static void CloseConnection(ConnectionInfo ci)
        {
            ci.Socket.Close();
            lock (connections) { connections.Remove(ci); Console.WriteLine(string.Format("Clients: {0}", connections.Count)); }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("TCP listener and proxy. Default mode is \"text\".");
            Console.WriteLine();
            Console.WriteLine("|--- \"exit\" to exit.                                  ---|");
            Console.WriteLine("|--- \"show text\" to display tcp data as text.         ---|");
            Console.WriteLine("|--- \"hide text\" to stop displaying tcp data as text. ---|");
            Console.WriteLine("|--- \"drop all\" to drop all connections.              ---|");
            Console.WriteLine();
            Console.Write("Please enter listen port number: ");
            bool portReady = false;
            string line = Console.ReadLine();
            while (line != "exit")
            {
                if (!portReady)
                {
                    try
                    {
                        port = int.Parse(line);
                        if (port > short.MaxValue || port < 2)
                        {
                            Console.WriteLine("Invalid port number.");
                            Console.Write("Please enter port number: ");
                        }
                        else
                        {
                            Start();
                            portReady = true;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("Invalid port number.");
                        Console.Write("Please enter port number: ");
                    }
                }
                else
                {
                    if (line == "show text")
                    {
                        lock (serverLock)
                        {
                            if (showText == false)
                            {
                                showText = true;
                                Console.WriteLine("Text output enabled.");
                            }
                        }
                    }
                    else if (line == "hide text")
                    {
                        lock (serverLock)
                        {
                            if (showText == true)
                            {
                                showText = false;
                                Console.WriteLine("Text output disabled.");
                            }
                        }
                    }
                    else if (line == "drop all")
                    {
                        lock (connections)
                        {
                            for (int i = connections.Count - 1; i >= 0; i--)
                            {
                                CloseConnection(connections[i]);
                            }
                        }
                    }
                    else
                    {
                        // send entered data to all clients
                        lock (connections)
                        {
                            foreach (ConnectionInfo conn in connections)
                            {
                                byte[] bytes = Encoding.UTF8.GetBytes(line + "\n");
                                conn.Socket.Send(bytes, bytes.Length,
                                    SocketFlags.None);
                            }
                        }
                    }
                }
                line = Console.ReadLine();
            }
            Console.Write("Shutting down server... ");
            lock (connections)
            {
                for (int i = connections.Count - 1; i >= 0; i--)
                {
                    CloseConnection(connections[i]);
                }
            }
            Console.WriteLine("Bye.");
            Thread.Sleep(500);
        }
    }
}
View Code

 

客户端:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace ConnectionClient
{
    public class SocketInfo
    {
        /// <summary>
        /// Socket receive buffer
        /// </summary>
        public byte[] buffer = new byte[255];
        /// <summary>
        /// Socket itself
        /// </summary>
        public Socket socket = null;
    }

    class Program
    {
        /* server info */
        private static string address;
        private static int port;
        private static IPEndPoint clientEndpoint;

        /// <summary>
        /// List of sockets, because this test client can spam the same server from multiple
        /// connections
        /// </summary>
        private static List<SocketInfo> socketList = new List<SocketInfo>();

        static void Start()
        {
            // Create socket based on stored server info (always connecting to the same server in this app)
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // store socket buffer together with socket in the same class
            SocketInfo info = new SocketInfo();
            info.socket = clientSocket;

            // when accessing socket list, always lock it.
            // if we had no need to so any action with all the sockets, we could do away
            // without locks
            lock (socketList)
            {
                socketList.Add(info);
            }
            Console.Write("Connecting... ");
            try
            {
                info.socket.Connect(clientEndpoint);
                Console.WriteLine("Done.");

                // begin receiving data. We pass SocketInfo over "state" argument
                // to avoid concurency issues, because ReceiveCallback will be called from unknown thread
                info.socket.BeginReceive(info.buffer, 0, info.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), info);
            }
            catch (Exception e)
            {
                lock (socketList)
                {
                    socketList.Remove(info);
                }
                Console.WriteLine("Fail.");
                Console.WriteLine(e);
            }
        }

        /// <summary>
        /// Receive callback is called from unknown system thread
        /// </summary>
        /// <param name="result"></param>
        static void ReceiveCallback(IAsyncResult result)
        {
            SocketInfo info = (SocketInfo)result.AsyncState;
            try
            {
                // have to call this to notify that we have received data
                int bytestoread = info.socket.EndReceive(result);
                if (bytestoread > 0)
                {
                    // in this case we are outputing data stream directly into console
                    string text = Encoding.UTF8.GetString(info.buffer, 0, bytestoread);
                    Console.Write(text);

                    // begin receive again, note how we don't need any locks!
                    info.socket.BeginReceive(info.buffer, 0, 255, SocketFlags.None, new AsyncCallback(ReceiveCallback), info);
                }
                else
                {
                    // in case client finished, remove it from the list
                    // this list can be accessed from any thread, so lock
                    lock (socketList)
                    {
                        socketList.Remove(info);
                    }
                    Console.WriteLine("Client finished normally.");
                    info.socket.Close();
                }
            }
            catch (Exception e)
            {
                // if problem occurs, remove socket from list too
                lock (socketList)
                {
                    socketList.Remove(info);
                }
                Console.WriteLine("Client Disconnected.");
                Console.WriteLine(e);
            }
        }

        /// <summary>
        /// Test TCP client
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("TCP client.");
            Console.WriteLine();
            Console.WriteLine("|--- \"exit\" to exit.                                  ---|");
            Console.WriteLine("|--- \"start {cn}\" to start {cn} number of connections.---|");
            Console.WriteLine();
            Console.Write("Please enter remote address and port: ");
            bool portReady = false;
            string line = Console.ReadLine();

            // input management stuff. boring.

            while (line != "exit")
            {
                if (!portReady)
                {
                    try
                    {
                        string[] ss = line.Split(':');
                        port = int.Parse(ss[1]);
                        IPAddress add = IPAddress.Parse(ss[0]);
                        clientEndpoint = new IPEndPoint(add, port);
                        address = clientEndpoint.Serialize().ToString();
                        if (port > short.MaxValue || port < 2)
                        {
                            Console.WriteLine("Invalid port.");
                            Console.Write("Please enter remote address and port: ");
                        }
                        else
                        {
                            Start();
                            portReady = true;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("Invalid address.");
                        Console.Write("Please enter remote address and port: ");
                    }
                }
                else
                {
                    if (line.StartsWith("start "))
                    {
                        int count = 0;
                        try
                        {
                            count = int.Parse(line.Substring("start ".Length));
                        }
                        catch { }
                        Console.WriteLine("Starting " + count + " connections.");
                        for (int i = 0; i < count; i++)
                        {
                            // this starts another connection
                            Start();
                        }
                    }
                    else
                    {
                        try
                        {
                            byte[] bytes = Encoding.UTF8.GetBytes(line + "\n");
                            lock (socketList)
                            {
                                foreach (SocketInfo info in socketList)
                                {
                                    info.socket.Send(bytes, bytes.Length, SocketFlags.None);
                                }
                            }
                        }
                        catch
                        {
                            Console.WriteLine("Unable to send data. Connection lost.");
                        }
                    }
                }
                line = Console.ReadLine();
            }
            Console.Write("Shutting down client... ");
            try
            {
                lock (socketList)
                {
                    for (int i = socketList.Count - 1; i >= 0; i--)
                    {
                        try {
                            socketList[i].socket.Shutdown(SocketShutdown.Both);
                            socketList[i].socket.Close();
                        } catch {}
                        socketList.RemoveAt(i);
                    }
                }
            }
            catch { }
            Console.WriteLine("Bye.");
            Thread.Sleep(500);
        }
    }
}
View Code

项目地址:https://github.com/Nercury/csharp-tcphelpers

4. 一个简单的基于TCP协议的聊天室(支持群聊和私聊)

运行时:.NET 2.0

简介:

1. 可以把服务端和客户端的 Command 枚举和 Data 类提取到一个公共的类库中。

2. Data 中是固定头部协议,但不支持中文,要支持中文,写入用户名、字符串时需要 Convert.ToBase64String(Encoding.UTF8.GetBytes(msg)),获取的时候,则 Encoding.UTF8.GetString(Convert.FromBase64String(msg))。

服务端:

Program.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Server
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new SGSserverForm());
        }
    }
}
View Code

SGSserverForm.cs

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace Server
{
    //The commands for interaction between the server and the client
    enum Command
    {
        Login,      //Log into the server
        Logout,     //Logout of the server
        Message,    //Send a text message to all the chat clients
        List,       //Get a list of users in the chat room from the server
        Null        //No command
    }

    public partial class SGSserverForm : Form
    {
        //The ClientInfo structure holds the required information about every
        //client connected to the server
        struct ClientInfo
        {
            public Socket socket;   //Socket of the client
            public string strName;  //Name by which the user logged into the chat room
        }

        //The collection of all clients logged into the room (an array of type ClientInfo)
        ArrayList clientList;

        //The main socket on which the server listens to the clients
        Socket serverSocket;

        byte[] byteData = new byte[1024];

        public SGSserverForm()
        {
            clientList = new ArrayList();
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {            
            try
            {
                //We are using TCP sockets
                serverSocket = new Socket(AddressFamily.InterNetwork, 
                                          SocketType.Stream, 
                                          ProtocolType.Tcp);
                
                //Assign the any IP of the machine and listen on port number 1000
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 1000);

                //Bind and listen on the given address
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(4);

                //Accept the incoming clients
                serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
            }
            catch (Exception ex)
            { 
                MessageBox.Show(ex.Message, "SGSserverTCP",                     
                    MessageBoxButtons.OK, MessageBoxIcon.Error); 
            }            
        }

        private void OnAccept(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = serverSocket.EndAccept(ar);

                //Start listening for more clients
                serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

                //Once the client connects then start receiving the commands from her
                clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, 
                    new AsyncCallback(OnReceive), clientSocket);                
            }
            catch (Exception ex)
            { 
                MessageBox.Show(ex.Message, "SGSserverTCP", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error); 
            }
        }

        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = (Socket)ar.AsyncState;
                clientSocket.EndReceive(ar);

                //Transform the array of bytes received from the user into an
                //intelligent form of object Data
                Data msgReceived = new Data(byteData);

                //We will send this object in response the users request
                Data msgToSend = new Data();

                byte [] message;
                string clientName;
                
                //If the message is to login, logout, or simple text message
                //then when send to others the type of the message remains the same
                msgToSend.cmdCommand = msgReceived.cmdCommand;
                msgToSend.strName = msgReceived.strName;

                switch (msgReceived.cmdCommand)
                {
                    case Command.Login:
                        
                        //When a user logs in to the server then we add her to our
                        //list of clients

                        ClientInfo clientInfo = new ClientInfo();
                        clientInfo.socket = clientSocket;      
                        clientInfo.strName = msgReceived.strName;

                        clientList.Add(clientInfo);
                        
                        //Set the text of the message that we will broadcast to all users
                        msgToSend.strMessage = "<<<" + msgReceived.strName + " has joined the room>>>";   
                        break;

                    case Command.Logout:                    
                        
                        //When a user wants to log out of the server then we search for her 
                        //in the list of clients and close the corresponding connection

                        int nIndex = 0;
                        foreach (ClientInfo client in clientList)
                        {
                            if (client.socket == clientSocket)
                            {
                                clientList.RemoveAt(nIndex);
                                break;
                            }
                            ++nIndex;
                        }
                        
                        clientSocket.Close();
                        
                        msgToSend.strMessage = "<<<" + msgReceived.strName + " has left the room>>>";
                        break;

                    case Command.Message:

                        //Set the text of the message that we will broadcast to all users
                        msgToSend.strMessage = msgReceived.strName + ": " + msgReceived.strMessage;
                        msgToSend.clientName = msgReceived.clientName;
                        break;

                    case Command.List:

                        //Send the names of all users in the chat room to the new user
                        msgToSend.cmdCommand = Command.List;
                        msgToSend.strName = null;
                        msgToSend.strMessage = null;
                        msgToSend.clientName = null;

                        //Collect the names of the user in the chat room
                        foreach (ClientInfo client in clientList)
                        {
                            //To keep things simple we use asterisk as the marker to separate the user names
                            msgToSend.strMessage += client.strName + "*";   
                        }

                        message = msgToSend.ToByte();

                        //Send the name of the users in the chat room
                        clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None,
                                new AsyncCallback(OnSend), clientSocket);                        
                        break;
                }

                if (msgToSend.cmdCommand != Command.List)   //List messages are not broadcasted
                {
                    message = msgToSend.ToByte();
                    if (msgToSend.clientName != null)
                        clientName = msgToSend.clientName;
                    else
                        clientName = null;

                    foreach (ClientInfo clientInfo in clientList)
                    {
                        if (clientInfo.socket != clientSocket ||
                            msgToSend.cmdCommand != Command.Login)
                        {
                            //Send the message to all users
                            if (clientName == null)
                            {
                                clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
                                                            new AsyncCallback(OnSend), clientInfo.socket);
                            }
                            else
                            {
                                if(clientInfo.strName==clientName)
                                {
                                    clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
                                                                new AsyncCallback(OnSend), clientInfo.socket);
                                }
                            }
                        }
                    }

                    //txtLog.Text += msgToSend.strMessage + "\r\n";
                    //MessageBox.Show(msgToSend.strMessage);
                }

                //If the user is logging out then we need not listen from her
                if (msgReceived.cmdCommand != Command.Logout)
                {
                    //Start listening to the message send by the user
                    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
                }
            }
            catch (Exception ex)
            { 
                MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.Error); 
            }
        }

        public void OnSend(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndSend(ar);                
            }
            catch (Exception ex)
            { 
                MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.Error); 
            }
        }
    }

    //The data structure by which the server and the client interact with 
    //each other
    class Data
    {
        //Default constructor
        public Data()
        {
            this.cmdCommand = Command.Null;
            this.strMessage = null;
            this.strName = null;
            this.clientName = null;
        }

        //Converts the bytes into an object of type Data
        public Data(byte[] data)
        {
            //The first four bytes are for the Command
            this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

            //The next four store the length of the name
            int nameLen = BitConverter.ToInt32(data, 4);

            //The next four store the length of the message
            int msgLen = BitConverter.ToInt32(data, 8);

            int clientLen = BitConverter.ToInt32(data, 12);

            //This check makes sure that strName has been passed in the array of bytes
            if (nameLen > 0)
                this.strName = Encoding.UTF8.GetString(data, 16, nameLen);
            else
                this.strName = null;

            //This checks for a null message field
            if (msgLen > 0)
                this.strMessage = Encoding.UTF8.GetString(data, 16 + nameLen, msgLen);
            else
                this.strMessage = null;

            if (clientLen > 0)
                this.clientName = Encoding.UTF8.GetString(data, 16 + nameLen + msgLen, clientLen);
            else
                this.clientName = null;
        }

        //Converts the Data structure into an array of bytes
        public byte[] ToByte()
        {
            List<byte> result = new List<byte>();

            //First four are for the Command
            result.AddRange(BitConverter.GetBytes((int)cmdCommand));

            //Add the length of the name
            if (strName != null)
                result.AddRange(BitConverter.GetBytes(strName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the message
            if (strMessage != null)
                result.AddRange(BitConverter.GetBytes(strMessage.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the clientName
            if (clientName != null)
                result.AddRange(BitConverter.GetBytes(clientName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Add the name
            if (strName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strName));

            //And, lastly we add the message text to our array of bytes
            if (strMessage != null)
                result.AddRange(Encoding.UTF8.GetBytes(strMessage));

            if (clientName != null)
                result.AddRange(Encoding.UTF8.GetBytes(clientName));

            return result.ToArray();
        }

        public string strName;      //Name by which the client logs into the room
        public string strMessage;   //Message text
        public string clientName;
        public Command cmdCommand;  //Command type (login, logout, send message, etcetera)
    } 
}
View Code

 

客户端:

 

下载地址:点击下载

项目地址:

https://github.com/iukash/TcpServerChat

https://github.com/iukash/TcpClientChat

5. 

aaa

谢谢浏览!