C#聊天程序

    技术2022-05-11  110

    /*=====================================================================  文件:      Wintalk.cs

      摘要:   演示如何使用 .NET创建聊天程序

    =====================================================================*/

    using System;using System.IO;using System.Text;using System.Threading;using System.Net;using System.Net.Sockets;using System.Drawing;using System.Windows.Forms;

    class App{            // Entry point    public static void Main(String[] args){                // If the args parse in known way then run the app        if(ParseArgs(args)){                       // Create a custom Talker object            Talker talker = new Talker(endPoint, client);            // Pass the object reference to a new form object            TalkForm form = new TalkForm(talker);                               // Start the talker "talking"            talker.Start();

                // Run the applications message pump            Application.Run(form);        }            }

        // Parsed Argument Storage    private static IPEndPoint endPoint;    private static bool client;

        // Parse command line arguments    private static bool ParseArgs(String[] args){        try{                    if(args.Length == 0){                client = false;                endPoint = new IPEndPoint(IPAddress.Any,5150);                return true;            }

                switch(Char.ToUpper(args[0][1])){            case 'L':                int port = 5150;                if(args.Length > 1){                   port = Convert.ToInt32(args[1]);                    }                endPoint = new IPEndPoint(IPAddress.Any,port);                client = false;                break;            case 'C':                port = 5150;                String address = "127.0.0.1";                client = true;                if(args.Length > 1){                    address = args[1];                    port = Convert.ToInt32(args[2]);                                                        }                                endPoint = new IPEndPoint(Dns.Resolve(address).AddressList[0], port);                break;            default:                ShowUsage();                return false;            }        }catch{            ShowUsage();            return false;        }                return true;    }

        // Show sample usage    private static void ShowUsage(){        MessageBox.Show("WinTalk [switch] [parameters...]/n/n"+            "  /L  [port]/t/t-- Listens on a port.  Default:  5150/n"+            "  /C  [address] [port]/t-- Connects to an address and port./n/n"+            "Example Server - /n"+            "Wintalk /L/n/n"+            "Example Client - /n"+            "Wintalk /C ServerMachine 5150","WinTalk Usage");    }}

    // UI class for the sampleclass TalkForm:Form {        public TalkForm(Talker talker) {        // Associate for method with the talker object        this.talker = talker;        talker.Notifications += new                 Talker.NotificationCallback(HandleTalkerNotifications);

            // Create a UI elements        Splitter talkSplitter = new Splitter();        Panel talkPanel = new Panel();       

            receiveText = new TextBox();        sendText = new TextBox();                 // we'll support up to 64k data in our text box controls        receiveText.MaxLength = sendText.MaxLength = 65536;        statusText = new Label();             // Initialize UI elements        receiveText.Dock = DockStyle.Top;        receiveText.Multiline = true;        receiveText.ScrollBars = ScrollBars.Both;        receiveText.Size = new Size(506, 192);        receiveText.TabIndex = 1;        receiveText.Text = "";        receiveText.WordWrap = false;        receiveText.ReadOnly = true;                talkPanel.Anchor = (AnchorStyles.Top|AnchorStyles.Bottom                    |AnchorStyles.Left|AnchorStyles.Right);        talkPanel.Controls.AddRange(new Control[] {sendText,                    talkSplitter,                    receiveText});        talkPanel.Size = new Size(506, 371);        talkPanel.TabIndex = 0;

            talkSplitter.Dock = DockStyle.Top;        talkSplitter.Location = new Point(0, 192);        talkSplitter.Size = new Size(506, 6);        talkSplitter.TabIndex = 2;        talkSplitter.TabStop = false;                statusText.Dock = DockStyle.Bottom;        statusText.Location = new Point(0, 377);        statusText.Size = new Size(507, 15);        statusText.TabIndex = 1;        statusText.Text = "Status:";

            sendText.Dock = DockStyle.Fill;        sendText.Location = new Point(0, 198);        sendText.Multiline = true;        sendText.ScrollBars = ScrollBars.Both;        sendText.Size = new Size(506, 173);        sendText.TabIndex = 0;        sendText.Text = "";        sendText.WordWrap = false;        sendText.TextChanged += new EventHandler(HandleTextChange);        sendText.Enabled = false;

            AutoScaleBaseSize = new Size(5, 13);        ClientSize = new Size(507, 392);        Controls.AddRange(new Control[] {statusText,                    talkPanel});        Text = "WinTalk";

            this.ActiveControl = sendText;         }   

        // When the app closes, dispose of the talker object    protected override void OnClosed(EventArgs e){        if(talker!=null){            // remove our notification handler            talker.Notifications -= new                 Talker.NotificationCallback(HandleTalkerNotifications);                        talker.Dispose();        }        base.OnClosed(e);    }        // Handle notifications from the talker object    private void HandleTalkerNotifications(        Talker.Notification notify, Object data){        switch(notify){        case Talker.Notification.Initialized:            break;        // Respond to status changes        case Talker.Notification.StatusChange:            Talker.Status status = (Talker.Status)data;            statusText.Text = String.Format("Status: {0}", status);            if(status == Talker.Status.Connected){                sendText.Enabled = true;            }            break;        // Respond to received text        case Talker.Notification.Received:            receiveText.Text = data.ToString();            receiveText.SelectionStart = Int32.MaxValue;            receiveText.ScrollToCaret();                    break;        // Respond to error notifications        case Talker.Notification.Error:                        Close(data.ToString());                    break;        // Respond to end        case Talker.Notification.End:                                                MessageBox.Show(data.ToString(), "Closing WinTalk");                         Close();            break;        default:            Close();            break;        }    }

        // Handle text change notifications and send talk    private void HandleTextChange(Object sender, EventArgs e){        if(talker != null){            talker.SendTalk((sender as TextBox).Text);        }            }  

        // Close with an explanation    private void Close(String message){           MessageBox.Show(message, "Error!");                Close();    }

        // Private UI elements    private TextBox receiveText;            private TextBox sendText;        private Label statusText;    private Talker talker;   }

    // An encapsulation of the Sockets class used for socket chattingclass Talker:IDisposable{    // Construct a talker     public Talker(IPEndPoint endPoint, bool client){        this.endPoint = endPoint;        this.client = client;

            socket = null;        reader = null;        writer = null;

            statusText = prevSendText = prevReceiveText = String.Empty;    }

        // Finalize a talker    ~Talker(){        Dispose();    }

        // Dispose of resources and surpress finalization    public void Dispose(){                GC.SuppressFinalize(this);        if(reader != null){            reader.Close();            reader = null;        }        if(writer != null){            writer.Close();            writer = null;        }        if(socket != null){            socket.Close();            socket = null;        }            }

        // Nested delegat class and matchine event    public delegate        void NotificationCallback(Notification notify, Object data);    public event NotificationCallback Notifications;

        // Nested enum for notifications    public enum Notification{        Initialized = 1,        StatusChange,        Received,        End,        Error    }

        // Nested enum for supported states    public enum Status{        Listening,        Connected    }

        // Start up the talker's functionality    public void Start(){        ThreadPool.QueueUserWorkItem(new WaitCallback(EstablishSocket));    }

        // Send text to remote connection    public void SendTalk(String newText){                        String send;        // Is this an append        if((prevSendText.Length <= newText.Length) && String.CompareOrdinal(            newText, 0, prevSendText, 0, prevSendText.Length)==0){            String append = newText.Substring(prevSendText.Length);            send = String.Format("A{0}:{1}", append.Length, append);        // or a complete replacement        }else{            send = String.Format("R{0}:{1}", newText.Length, newText);        }           // Send the data and flush it out        writer.Write(send);        writer.Flush();        // Save the text for future comparison        prevSendText = newText;    }

        // Send a status notification    private void SetStatus(Status status){        this.status = status;        Notifications(Notification.StatusChange, status);    }

        // Establish a socket connection and start receiving    private void EstablishSocket(Object state){                       try{            // If not client, setup listner            if(!client){                Socket listener;                                try{                    listener = new Socket(AddressFamily.InterNetwork,                        SocketType.Stream, ProtocolType.Tcp);                    listener.Blocking = true;                    listener.Bind(endPoint);                    SetStatus(Status.Listening);                                        listener.Listen(0);                    socket = listener.Accept();                    listener.Close();                                                }catch(SocketException e){                    // If there is already a listener on this port try client                    if(e.ErrorCode == 10048){                        client = true;                        endPoint = new IPEndPoint(                            Dns.Resolve("127.0.0.1").AddressList[0], endPoint.Port);                    }else{                        Notifications(                            Notification.Error,                             "Error Initializing Socket:/n"+e.ToString());                                            }                }                                                }

                // Try a client connection            if(client){                Socket temp = new                     Socket(AddressFamily.InterNetwork,                    SocketType.Stream,ProtocolType.Tcp);                temp.Blocking = true;                temp.Connect(endPoint);                socket = temp;            }

                // If it all worked out, create stream objects            if(socket != null){                SetStatus(Status.Connected);                                 NetworkStream stream = new NetworkStream(socket);                reader = new StreamReader(stream);                writer = new StreamWriter(stream);                Notifications(Notification.Initialized, this);                            }else{                Notifications(Notification.Error,                     "Failed to Establish Socket");            }

                // Start receiving talk            // Note: on w2k and later platforms, the NetworkStream.Read()            // method called in ReceiveTalk will generate an exception when            // the remote connection closes. We handle this case in our            // catch block below.            ReceiveTalk();

                // On Win9x platforms, NetworkStream.Read() returns 0 when            // the remote connection closes, prompting a graceful return            // from ReceiveTalk() above. We will generate a Notification.End            // message here to handle the case and shut down the remaining            // WinTalk instance.            Notifications(Notification.End, "Remote connection has closed.");                    }catch(IOException e){             SocketException sockExcept = e.InnerException as SocketException;             if(sockExcept != null && 10054 == sockExcept.ErrorCode){                Notifications(Notification.End, "Remote connection has closed.");            }else{    if (Notifications != null)     Notifications(Notification.Error, "Socket Error:/n"+e.Message);            }                        }catch(Exception e){                          Notifications(Notification.Error, "Socket Error:/n"+e.Message);        }    }

        // Receive chat from remote client    private void ReceiveTalk(){        char[] commandBuffer = new char[20];        char[] oneBuffer = new char[1];        int readMode = 1;        int counter = 0;                StringBuilder text = new StringBuilder();

            while(readMode != 0){            if(reader.Read(oneBuffer, 0, 1)==0){                readMode = 0;                continue;            }

                switch(readMode){            case 1:                        if(counter == commandBuffer.Length){                    readMode = 0;                    continue;                }                if(oneBuffer[0] != ':'){                    commandBuffer[counter++] = oneBuffer[0];                }else{                    counter = Convert.ToInt32(                        new String(commandBuffer, 1, counter-1));                    if(counter>0){                        readMode = 2;                                                    text.Length = 0;                    }else if(commandBuffer[0] == 'R'){                        counter = 0;                        prevReceiveText = String.Empty;                        Notifications(Notification.Received, prevReceiveText);                    }                }                break;            case 2:                text.Append(oneBuffer[0]);                if(--counter == 0){                    switch(commandBuffer[0]){                    case 'R':                        prevReceiveText = text.ToString();                        break;                    default:                        prevReceiveText += text.ToString();                        break;                    }                                        readMode = 1;

                        Notifications(Notification.Received, prevReceiveText);                                    }                break;            default:                readMode = 0;                continue;            }                    }            }

        private Socket socket;

        private TextReader reader;    private TextWriter writer;        bool client;    IPEndPoint endPoint;

        private String prevSendText;    private String prevReceiveText;    private String statusText;

        private Status status;    }

    Microsoft.NET FrameworkSDK带这个例子.


    最新回复(0)