首页 > 开发 > 综合 > 正文

C#聊天程序

2024-07-21 02:27:25
字体:
来源:转载
供稿:网友

/*=====================================================================
  文件:      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 sample
class 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 chatting
class 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带这个例子.


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表