home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 June (DVD) / DPPRO0605DVD.iso / dotNETSDK / SETUP.EXE / netfxsd1.cab / FL_WinTalk_cs________.3643236F_FC70_11D3_A536_0090278A1BB8 < prev    next >
Encoding:
Text File  |  2002-04-19  |  17.7 KB  |  518 lines

  1. /*=====================================================================
  2.   File:      Wintalk.cs
  3.  
  4.   Summary:   Demonstrates how to create a socket chat application
  5.              using various .NET Framework library types.
  6.  
  7. ---------------------------------------------------------------------
  8.   This file is part of the Microsoft .NET Framework SDK Code Samples.
  9.  
  10.   Copyright (C) 2000 Microsoft Corporation.  All rights reserved.
  11.  
  12. This source code is intended only as a supplement to Microsoft
  13. Development Tools and/or on-line documentation.  See these other
  14. materials for detailed information regarding Microsoft code samples.
  15.  
  16. THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  17. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  18. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  19. PARTICULAR PURPOSE.
  20. =====================================================================*/
  21.  
  22. using System;
  23. using System.Globalization;
  24. using System.IO;
  25. using System.Text;
  26. using System.Threading;
  27. using System.Net;
  28. using System.Net.Sockets;
  29. using System.Drawing;
  30. using System.Windows.Forms;
  31.  
  32. class App{        
  33.     // Entry point
  34.     public static void Main(String[] args){        
  35.         // If the args parse in known way then run the app
  36.         if(ParseArgs(args)){           
  37.             // Create a custom Talker object
  38.             Talker talker = new Talker(endPoint, client);
  39.             // Pass the object reference to a new form object
  40.             TalkForm form = new TalkForm(talker);                   
  41.             // Start the talker "talking"
  42.             talker.Start();
  43.  
  44.             // Run the applications message pump
  45.             Application.Run(form);
  46.         }        
  47.     }
  48.  
  49.     // Parsed Argument Storage
  50.     private static IPEndPoint endPoint;
  51.     private static bool client;
  52.  
  53.     // Parse command line arguments
  54.     private static bool ParseArgs(String[] args){
  55.         try{        
  56.             if(args.Length == 0){
  57.                 client = false;
  58.                 endPoint = new IPEndPoint(IPAddress.Any,5150);
  59.                 return true;
  60.             }
  61.             if (args[0][0]!='/' && args[0][0]!='-') 
  62.             {
  63.                 ShowUsage();
  64.                 return false;
  65.             }
  66.             switch(Char.ToUpper(args[0][1], CultureInfo.InvariantCulture)){
  67.             case 'L':
  68.                 int port = 5150;
  69.                 if(args.Length > 1){
  70.                    port = Convert.ToInt32(args[1]);    
  71.                 }
  72.                 endPoint = new IPEndPoint(IPAddress.Any,port);
  73.                 client = false;
  74.                 break;
  75.             case 'C':
  76.                 port = 5150;
  77.                 String address = "127.0.0.1";
  78.                 client = true;
  79.                 if(args.Length > 1){
  80.                     address = args[1];
  81.                     port = Convert.ToInt32(args[2]);                                        
  82.                 }                
  83.                 endPoint = new IPEndPoint(Dns.Resolve(address).AddressList[0], port);
  84.                 break;
  85.             default:
  86.                 ShowUsage();
  87.                 return false;
  88.             }
  89.         }catch{
  90.             ShowUsage();
  91.             return false;
  92.         }    
  93.     
  94.         return true;
  95.     }
  96.  
  97.     // Show sample usage
  98.     private static void ShowUsage(){
  99.         MessageBox.Show("WinTalk [switch] [parameters...]\n\n"+
  100.             "  /L  [port]\t\t-- Listens on a port.  Default:  5150\n"+
  101.             "  /C  [address] [port]\t-- Connects to an address and port.\n\n"+
  102.             "Example Server - \n"+
  103.             "Wintalk /L\n\n"+
  104.             "Example Client - \n"+
  105.             "Wintalk /C ServerMachine 5150","WinTalk Usage");
  106.     }
  107. }
  108.  
  109. // UI class for the sample
  110. class TalkForm:Form {    
  111.     public TalkForm(Talker talker) {
  112.         // Associate for method with the talker object
  113.         this.talker = talker;
  114.         talker.Notifications += new 
  115.                 Talker.NotificationCallback(HandleTalkerNotifications);
  116.  
  117.         // Create a UI elements
  118.         Splitter talkSplitter = new Splitter();
  119.         Panel talkPanel = new Panel();        
  120.  
  121.         receiveText = new TextBox();
  122.         sendText = new TextBox(); 
  123.         
  124.         // we'll support up to 64k data in our text box controls
  125.         receiveText.MaxLength = sendText.MaxLength = 65536;
  126.         statusText = new Label();
  127.      
  128.         // Initialize UI elements
  129.         receiveText.Dock = DockStyle.Top;
  130.         receiveText.Multiline = true;
  131.         receiveText.ScrollBars = ScrollBars.Both;
  132.         receiveText.Size = new Size(506, 192);
  133.         receiveText.TabIndex = 1;
  134.         receiveText.Text = "";
  135.         receiveText.WordWrap = false;
  136.         receiveText.ReadOnly = true;
  137.         
  138.         talkPanel.Anchor = (AnchorStyles.Top|AnchorStyles.Bottom
  139.                     |AnchorStyles.Left|AnchorStyles.Right);
  140.         talkPanel.Controls.AddRange(new Control[] {sendText,
  141.                     talkSplitter,
  142.                     receiveText});
  143.         talkPanel.Size = new Size(506, 371);
  144.         talkPanel.TabIndex = 0;
  145.  
  146.         talkSplitter.Dock = DockStyle.Top;
  147.         talkSplitter.Location = new Point(0, 192);
  148.         talkSplitter.Size = new Size(506, 6);
  149.         talkSplitter.TabIndex = 2;
  150.         talkSplitter.TabStop = false;
  151.         
  152.         statusText.Dock = DockStyle.Bottom;
  153.         statusText.Location = new Point(0, 377);
  154.         statusText.Size = new Size(507, 15);
  155.         statusText.TabIndex = 1;
  156.         statusText.Text = "Status:";
  157.  
  158.         sendText.Dock = DockStyle.Fill;
  159.         sendText.Location = new Point(0, 198);
  160.         sendText.Multiline = true;
  161.         sendText.ScrollBars = ScrollBars.Both;
  162.         sendText.Size = new Size(506, 173);
  163.         sendText.TabIndex = 0;
  164.         sendText.Text = "";
  165.         sendText.WordWrap = false;
  166.         sendText.TextChanged += new EventHandler(HandleTextChange);
  167.         sendText.Enabled = false;
  168.  
  169.         AutoScaleBaseSize = new Size(5, 13);
  170.         ClientSize = new Size(507, 392);
  171.         Controls.AddRange(new Control[] {statusText,
  172.                     talkPanel});
  173.         Text = "WinTalk";
  174.     }    
  175.  
  176.     // When the app closes, dispose of the talker object
  177.     protected override void OnClosed(EventArgs e){
  178.         if(talker!=null){
  179.             // remove our notification handler
  180.             talker.Notifications -= new 
  181.                 Talker.NotificationCallback(HandleTalkerNotifications);
  182.             
  183.             talker.Dispose();
  184.         }
  185.         base.OnClosed(e);
  186.     }
  187.  
  188.     // Handle notifications from the talker object
  189.     private void HandleTalkerNotifications(
  190.         Talker.Notification notify, Object data){
  191.         switch(notify){
  192.         case Talker.Notification.Initialized:
  193.             break;
  194.         // Respond to status changes
  195.         case Talker.Notification.StatusChange:
  196.             Talker.Status status = (Talker.Status)data;
  197.             statusText.Text = String.Format("Status: {0}", status);
  198.             if(status == Talker.Status.Connected){
  199.                 sendText.Enabled = true;
  200.                 sendText.Focus();
  201.             }
  202.             break;
  203.         // Respond to received text
  204.         case Talker.Notification.ReceivedAppend:
  205.             receiveText.AppendText(data.ToString());
  206.             //receiveText.SelectionStart = Int32.MaxValue;
  207.             //receiveText.ScrollToCaret();        
  208.             break;
  209.         case Talker.Notification.ReceivedRefresh:
  210.             receiveText.Text = data.ToString();
  211.             receiveText.SelectionStart = Int32.MaxValue;
  212.             receiveText.ScrollToCaret();        
  213.             break;
  214.         // Respond to error notifications
  215.         case Talker.Notification.Error:            
  216.             Close(data.ToString());        
  217.             break;
  218.         // Respond to end
  219.         case Talker.Notification.End:                                    
  220.             // Don't send any more text
  221.             sendText.TextChanged -= new EventHandler(HandleTextChange); 
  222.             MessageBox.Show(this, data.ToString(), "Closing WinTalk");             
  223.             Close();
  224.             break;
  225.         default:
  226.             Close();
  227.             break;
  228.         }
  229.     }
  230.  
  231.     // Handle text change notifications and send talk
  232.     private void HandleTextChange(Object sender, EventArgs e){
  233.         if(talker != null){
  234.             talker.SendTalk((sender as TextBox).Text);
  235.         }        
  236.     }   
  237.  
  238.     // Close with an explanation
  239.     private void Close(String message){   
  240.         MessageBox.Show(message, "Error!");        
  241.         Close();
  242.     }
  243.  
  244.     // Private UI elements
  245.     private TextBox receiveText;        
  246.     private TextBox sendText;    
  247.     private Label statusText;
  248.     private Talker talker;   
  249. }
  250.  
  251. // An encapsulation of the Sockets class used for socket chatting
  252. class Talker:IDisposable{
  253.     // Construct a talker 
  254.     public Talker(IPEndPoint endPoint, bool client){
  255.         this.endPoint = endPoint;
  256.         this.client = client;
  257.  
  258.         socket = null;
  259.         reader = null;
  260.         writer = null;
  261.  
  262.         statusText = prevSendText = prevReceiveText = String.Empty;
  263.     }
  264.  
  265.     // Finalize a talker
  266.     ~Talker(){
  267.         Dispose();
  268.     }
  269.  
  270.     // Dispose of resources and surpress finalization
  271.     public void Dispose(){        
  272.         GC.SuppressFinalize(this);
  273.         if(reader != null){
  274.             reader.Close();
  275.             reader = null;
  276.         }
  277.         if(writer != null){
  278.             writer.Close();
  279.             writer = null;
  280.         }
  281.         if(socket != null){
  282.             socket.Close();
  283.             socket = null;
  284.         }        
  285.     }
  286.  
  287.     // Nested delegat class and matchine event
  288.     public delegate 
  289.        void NotificationCallback(Notification notify, Object data);
  290.     public event NotificationCallback Notifications;
  291.  
  292.     // Nested enum for notifications
  293.     public enum Notification{
  294.         Initialized = 1,
  295.         StatusChange,
  296.         ReceivedRefresh,
  297.         ReceivedAppend,
  298.         End,
  299.         Error
  300.     }
  301.  
  302.     // Nested enum for supported states
  303.     public enum Status{
  304.         Listening,
  305.         Connected
  306.     }
  307.  
  308.     // Start up the talker's functionality
  309.     public void Start(){
  310.         ThreadPool.QueueUserWorkItem(new WaitCallback(EstablishSocket));
  311.     }
  312.  
  313.     // Send text to remote connection
  314.     public void SendTalk(String newText){                
  315.         String send;
  316.         // Is this an append
  317.         if((prevSendText.Length <= newText.Length) && String.CompareOrdinal(
  318.             newText, 0, prevSendText, 0, prevSendText.Length)==0){
  319.             String append = newText.Substring(prevSendText.Length);
  320.             send = String.Format("A{0}:{1}", append.Length, append);
  321.         // or a complete replacement
  322.         }else{
  323.             send = String.Format("R{0}:{1}", newText.Length, newText);
  324.         }   
  325.         // Send the data and flush it out
  326.         writer.Write(send);
  327.         writer.Flush();
  328.         // Save the text for future comparison
  329.         prevSendText = newText;
  330.     }
  331.  
  332.     // Send a status notification
  333.     private void SetStatus(Status status){
  334.         this.status = status;
  335.         Notifications(Notification.StatusChange, status);
  336.     }
  337.  
  338.     // Establish a socket connection and start receiving
  339.     private void EstablishSocket(Object state){               
  340.         NetworkStream stream = null;
  341.         try{
  342.             // If not client, setup listner
  343.             if(!client){
  344.                 Socket listener;
  345.                 
  346.                 try{
  347.                     listener = new Socket(AddressFamily.InterNetwork,
  348.                         SocketType.Stream, ProtocolType.Tcp);
  349.                     listener.Blocking = true;
  350.                     listener.Bind(endPoint);
  351.                     SetStatus(Status.Listening);                    
  352.                     listener.Listen(0);
  353.                     socket = listener.Accept();
  354.                     listener.Close();          
  355.                     stream = new NetworkStream(socket);
  356.                     reader = new StreamReader(stream);
  357.                     writer = new StreamWriter(stream);
  358.                     writer.Write("WINTALK .NET");
  359.                     writer.Flush();
  360.                 }catch(SocketException e){
  361.                     // If there is already a listener on this port try client
  362.                     if(e.ErrorCode == 10048){
  363.                         client = true;
  364.                         endPoint = new IPEndPoint(
  365.                             Dns.Resolve("127.0.0.1").AddressList[0], endPoint.Port);
  366.                     }else{
  367.                         Notifications(
  368.                             Notification.Error, 
  369.                             "Error Initializing Socket:\n"+e.ToString());                        
  370.                     }
  371.                 }                                    
  372.             }
  373.  
  374.             // Try a client connection
  375.             if(client){
  376.                 Socket temp = new 
  377.                     Socket(AddressFamily.InterNetwork,
  378.                     SocketType.Stream,ProtocolType.Tcp);
  379.                 temp.Blocking = true;
  380.                 temp.Connect(endPoint);
  381.                 socket = temp;
  382.                 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);
  383.                 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);
  384.                 stream = new NetworkStream(socket);
  385.                 reader = new StreamReader(stream);
  386.                 writer = new StreamWriter(stream);
  387.                 char[] handshake = new char[12];
  388.                 try
  389.                 {
  390.                     if (!(reader.Read(handshake,0,12)>0 && new string(handshake)=="WINTALK .NET"))
  391.                     {
  392.                         socket.Close();
  393.                         socket = null;
  394.                     }
  395.                     else
  396.                     {
  397.                         socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout , 0);
  398.                         socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 0);
  399.                     }
  400.                 }
  401.                 catch
  402.                 {
  403.                     socket.Close();
  404.                     socket = null;
  405.                 }
  406.             }
  407.  
  408.             // If it all worked out, create stream objects
  409.             if(socket != null){
  410.                 SetStatus(Status.Connected);                 
  411.                 Notifications(Notification.Initialized, this);                
  412.                 // Start receiving talk
  413.                 // Note: on w2k and later platforms, the NetworkStream.Read()
  414.                 // method called in ReceiveTalk will generate an exception when
  415.                 // the remote connection closes. We handle this case in our
  416.                 // catch block below.
  417.                 ReceiveTalk();
  418.  
  419.                 // On Win9x platforms, NetworkStream.Read() returns 0 when
  420.                 // the remote connection closes, prompting a graceful return
  421.                 // from ReceiveTalk() above. We will generate a Notification.End
  422.                 // message here to handle the case and shut down the remaining
  423.                 // WinTalk instance.
  424.                 Notifications(Notification.End, "Remote connection has closed.");
  425.             }
  426.             else
  427.             {
  428.                 Notifications(Notification.Error, 
  429.                     "Failed to Establish Socket, did you specify the correct port?");
  430.             }
  431.         }catch(IOException e){ 
  432.             SocketException sockExcept = e.InnerException as SocketException; 
  433.             if(sockExcept != null && 10054 == sockExcept.ErrorCode){
  434.                 Notifications(Notification.End, "Remote connection has closed.");
  435.             }else{
  436.                 if (Notifications != null)
  437.                     Notifications(Notification.Error, "Socket Error:\n"+e.Message);
  438.             }                
  439.         }catch(Exception e){              
  440.             Notifications(Notification.Error, "Socket Error:\n"+e.Message);
  441.         }
  442.     }
  443.  
  444.     // Receive chat from remote client
  445.     private void ReceiveTalk(){
  446.         char[] commandBuffer = new char[20];
  447.         char[] oneBuffer = new char[1];
  448.         int readMode = 1;
  449.         int counter = 0;        
  450.         StringBuilder text = new StringBuilder();
  451.  
  452.         while(readMode != 0){
  453.             if(reader.Read(oneBuffer, 0, 1)==0){
  454.                 readMode = 0;
  455.                 continue;
  456.             }
  457.  
  458.             switch(readMode){
  459.             case 1:        
  460.                 if(counter == commandBuffer.Length){
  461.                     readMode = 0;
  462.                     continue;
  463.                 }
  464.                 if(oneBuffer[0] != ':'){
  465.                     commandBuffer[counter++] = oneBuffer[0];
  466.                 }else{
  467.                     counter = Convert.ToInt32(
  468.                         new String(commandBuffer, 1, counter-1));
  469.                     if(counter>0){
  470.                         readMode = 2;                            
  471.                         text.Length = 0;
  472.                     }else if(commandBuffer[0] == 'R'){
  473.                         counter = 0;
  474.                         prevReceiveText = String.Empty;
  475.                         Notifications(Notification.ReceivedRefresh, prevReceiveText);
  476.                     }
  477.                 }
  478.                 break;
  479.             case 2:
  480.                 text.Append(oneBuffer[0]);
  481.                 if(--counter == 0){
  482.                     switch(commandBuffer[0]){
  483.                     case 'R':
  484.                         prevReceiveText = text.ToString();
  485.                         Notifications(Notification.ReceivedRefresh, prevReceiveText);                    
  486.                         break;
  487.                     default:
  488.                         string newText = text.ToString();
  489.                         prevReceiveText += newText;
  490.                         Notifications(Notification.ReceivedAppend, newText);                    
  491.                         break;
  492.                     }                    
  493.                     readMode = 1;
  494.                     
  495.                 }
  496.                 break;
  497.             default:
  498.                 readMode = 0;
  499.                 continue;
  500.             }            
  501.         }        
  502.     }
  503.  
  504.     private Socket socket;
  505.  
  506.     private TextReader reader;
  507.     private TextWriter writer;
  508.     
  509.     bool client;
  510.     IPEndPoint endPoint;
  511.  
  512.     private String prevSendText;
  513.     private String prevReceiveText;
  514.     private String statusText;
  515.  
  516.     private Status status;    
  517. }
  518.