home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples.exe / Wintalk / CS / WinTalk.cs < prev   
Encoding:
Text File  |  2000-06-23  |  19.8 KB  |  639 lines

  1. /*+==========================================================================
  2.   File:      wintalk.cs
  3.  
  4.   Summary:   This contains the front-end logic to wintalk, and entry point.
  5.              This application demonstrates the use of WFC and System.Net.DLL.
  6.  
  7.              Wintalk starts with a dialog that with to multi-line edit boxes
  8.              and two buttons (one grayed out).  In the background, it spins 
  9.              off a thread (ServerConnectionThread) which begins listening on 
  10.              TCP/IP port 5000.  When an incoming connection arrives, the 
  11.              ServerConnectionThread posts a message to the UI thread to 
  12.              un-gray the "disconnect" button, and gray out the "connect" 
  13.              button, and a client thread is started which receive all data
  14.              and sends the characters to the top edit window.  The user types 
  15.              in the bottom edit window to transmit to the remote end.
  16.  
  17.              WFC's InvokeAsync is used to provide a thread switch from one 
  18.              of the "worker" threads (such as ServerConnectionThread) to 
  19.              the UI thread (which is started from Main, and messages pumped
  20.              in Application.Run).
  21.              
  22.   Classes:   Wintalk
  23.  
  24.   Functions: 
  25.          Overrides:              Dispose
  26.  
  27.          Initialization:         InitForm
  28.  
  29.          Thread procedures:      ClientConnectionThreadProc, 
  30.                                  ServerConnectionThreadProc
  31.  
  32.          Async Invoked Methods:  OnClientActive, OnClientClosed,
  33.                                  OnServerAccept, OnServerReject
  34.  
  35.          Other:                  EnableClientConnection, 
  36.                                  DisableClientConnection
  37.              
  38.          UI Event Handlers:      panel1_resize, button1_click, 
  39.                                  button2_click, WinTalk_activate
  40.  
  41.          Entry point:            Main
  42.  
  43. ----------------------------------------------------------------------------
  44.   This file is part of the Microsoft NGWS Samples.
  45.  
  46.   Copyright (C) 1998-2000 Microsoft Corporation.  All rights reserved.
  47. ==========================================================================+*/
  48.  
  49. using System;
  50. using System.Threading;
  51. using System.ComponentModel;
  52. using System.Core;
  53. using System.WinForms;
  54. using System.Runtime.InteropServices;
  55. using System.Drawing;
  56. using System.Net;
  57. using System.Net.Sockets;
  58.  
  59. // define delegates to be used with AsyncInvoke
  60. delegate void AsyncInvokeDelegate();
  61. delegate void AsyncInvokeStringDelegate(String str);
  62.  
  63.  
  64. public class WinTalk : Form
  65. {
  66.     protected Socket ClientConnection = null;
  67.     protected Socket ServerConnection = null;
  68.     
  69.     public int ServerPort = 5000;
  70.  
  71.     protected Thread ClientConnectionThread = null;
  72.     protected Thread ServerConnectionThread = null;
  73.  
  74.     protected String m_ListenStr;
  75.     
  76.     protected bool bIsInDispose = false;
  77.     
  78. /*****************************************************************************
  79.  Constructor : WinTalk
  80.  
  81.  Abstract:     Constructs an instance of Wintalk, calls Window's default
  82.                contructor.
  83.             
  84.  Input Parameters: port(int)
  85.  
  86. ******************************************************************************/
  87.     public WinTalk(int port)
  88.     {
  89.         this.ServerPort = port;
  90.  
  91.         InitForm();        
  92.  
  93.         // start "Listening" thread
  94.         ServerConnectionThread = new Thread(new ThreadStart(this.ServerConnectionThreadProc));
  95.         ServerConnectionThread.Start();
  96.     }
  97.  
  98. /*****************************************************************************
  99.  Function:     Dispose
  100.  
  101.  Abstract:     Overrides Form.Dispose, cleans up the component list.
  102.             
  103.  Input Parameters: (None)
  104.  
  105.  Returns: void
  106. ******************************************************************************/
  107.     public override void Dispose()
  108.     {
  109.         bIsInDispose = true;
  110.         base.Dispose();
  111.         components.Dispose();        
  112.         
  113.         DisableClientConnection();
  114.         
  115.         // Kill server thread
  116.         try {
  117.             if (ServerConnection != null)
  118.                 ServerConnection.Close();
  119.         }
  120.         catch
  121.         {
  122.             Console.WriteLine("Error while closing server connection!!!!!");
  123.         }
  124.         ServerConnection = null;
  125.         
  126.         if (ServerConnectionThread != null)
  127.                 ServerConnectionThread.Join();
  128.         ServerConnectionThread = null;
  129.  
  130.         if (ClientConnectionThread != null)
  131.             ClientConnectionThread.Join();
  132.         ClientConnectionThread = null;
  133.     }
  134.  
  135. /*****************************************************************************
  136.  Function:     OnClientActive
  137.  
  138.  Abstract:     Invoked asynchronously when a connection becomes active.
  139.             
  140.  Input Parameters: (None)
  141.  
  142.  Returns: void
  143. ******************************************************************************/
  144.     protected void OnClientActive()
  145.     {
  146.         button1.Enabled = false;
  147.         button2.Enabled = true;
  148.         edit2.Focus(); // helps to eliminate confusion, sets focus to SendEdit
  149.         
  150.         IPEndPoint ep = (IPEndPoint)ClientConnection.RemoteEndpoint;
  151.  
  152.         String addr = DNS.InetNtoa(ep.Address);
  153.         int port = ep.Port;
  154.         String host = DNS.GetHostByAddr(addr).Hostname;
  155.         String s = "Talking to "+addr+":"+port.ToString()+"("+host+")";
  156.         Console.WriteLine(s);
  157.         label1.Text = s;
  158.     }
  159.  
  160. /*****************************************************************************
  161.  Function:     OnClientClosed
  162.  
  163.  Abstract:     Invoked asynchronously when the active connection is closed
  164.             
  165.  Input Parameters: (None)
  166.  
  167.  Returns: void
  168. ******************************************************************************/
  169.     protected void OnClientClosed()
  170.     {
  171.         edit1.Append("\r\n****Notice: Connection Closed****\r\n");
  172.         button1.Enabled = true;
  173.         button2.Enabled = false;
  174.         label1.Text = m_ListenStr;
  175.     }
  176.     
  177. /*****************************************************************************
  178.  Function:     OnServerAccept
  179.  
  180.  Abstract:     Invoked asynchronously when an incoming connection is accepted
  181.                by the server thread.
  182.             
  183.  Input Parameters: (None)
  184.  
  185.  Returns: void
  186. ******************************************************************************/
  187.     protected void OnServerAccept()
  188.     {
  189.         edit1.Append("\r\n****CONNECTION ACTIVE****\r\n");
  190.         WindowState = FormWindowState.Normal;
  191.         //Windows.SetForegroundWindow(Handle);
  192.     }
  193.     
  194. /*****************************************************************************
  195.  Function:     OnServerReject
  196.  
  197.  Abstract:     Invoked asynchronously when an incoming connection is rejected
  198.                by the server thread.
  199.             
  200.  Input Parameters: (None)
  201.  
  202.  Returns: void
  203. ******************************************************************************/
  204.     protected void OnServerReject()
  205.     {
  206.         edit1.Append("\r\n****Warning: Incoming being rejected****\r\n");
  207.     }
  208.  
  209. /*****************************************************************************
  210.  Function:     EnableClientConnection
  211.  
  212.  Abstract:     Called when "ClientConnection" becomes valid.  Resets UI to 
  213.                proper state and spins off a ClientConnectionThread thread.
  214.             
  215.  Input Parameters: None
  216.  
  217.  Returns: Void
  218. ******************************************************************************/
  219.     public void EnableClientConnection()
  220.     {
  221.         if (ClientConnectionThread != null) {
  222.             throw new ApplicationException("Client reader thread "+
  223.                                            "(ClientConnectionThread) already "+
  224.                                            "active!!");
  225.         }
  226.         ClientConnectionThread = new Thread(new ThreadStart(this.ClientConnectionThreadProc));
  227.         ClientConnectionThread.Start();
  228.         BeginInvoke(new AsyncInvokeDelegate(this.OnClientActive));
  229.         edit2.SetClientConnection(ClientConnection);
  230.     }
  231.     
  232. /*****************************************************************************
  233.  Function:     DisableClientConnection
  234.  
  235.  Abstract:     Called when "ClientConnection" becomes invalid, or actually
  236.                closes ClientConnection.  Resets UI to proper state and if not 
  237.                called from ClientConnectionThread, waits for this thread to 
  238.                terminate.
  239.             
  240.  Input Parameters: None
  241.  
  242.  Returns: Void
  243. ******************************************************************************/
  244.     public void DisableClientConnection()
  245.     {
  246.         try {
  247.             edit2.SetClientConnection(null);
  248.             lock(this) {
  249.                 if (ClientConnection != null) {
  250.                     Console.WriteLine("DisableClientConnection: "+
  251.                             "closing connection");
  252.                     ClientConnection.Close();
  253.                     ClientConnection = null;
  254.                 }
  255.             }
  256.         }
  257.         catch (Exception e) {
  258.             MessageBox.Show(this,e.Message,"Close Error");
  259.         }
  260.         if (Thread.CurrentThread == ClientConnectionThread) {
  261.             ClientConnectionThread = null;
  262.             if (this.HandleCreated) {
  263.                 BeginInvoke(new AsyncInvokeDelegate(this.OnClientClosed));
  264.             }
  265.         } else {
  266.             if (ClientConnectionThread != null) {
  267.                 ClientConnectionThread.Join();
  268.                 ClientConnectionThread = null;
  269.             }
  270.         }
  271.     }
  272.  
  273. /*****************************************************************************
  274.  Function:     ClientConnectionThreadProc
  275.  
  276.  Abstract:     Called when a client connection is made (click the "connect"
  277.                button, or incoming connection is made).  This thread is
  278.                created and started from the "EnableClientConnection" method.
  279.             
  280.  Input Parameters: None
  281.  
  282.  Returns: Void
  283. ******************************************************************************/
  284.     protected void ClientConnectionThreadProc()
  285.     {
  286.         Console.WriteLine("ClientConnectionThreadProc thread is starting");
  287.         try {
  288.             char c = '\0';
  289.         
  290.             bool ignore_next_return = false;
  291.             byte[] b = new byte[1];
  292.  
  293.             // read one character at a time from the Socket
  294.             while (ClientConnection != null && ClientConnection.Receive(b,b.Length,0) > 0) {
  295.                 c = (char)b[0];
  296.                 if (ignore_next_return && (c == '\r' || c == '\n')) {
  297.                     ignore_next_return = false;
  298.                     continue;
  299.                 }
  300.                 ignore_next_return = false;
  301.  
  302.                 if (c == '\b') {
  303.                     // backspace character causes use to truncate one char
  304.                     // off of the edit control
  305.                     edit1.BeginInvoke(new AsyncInvokeDelegate(edit1.TruncateOneCharFromEnd));
  306.                     continue;
  307.                 }
  308.  
  309.                 String str = null;
  310.  
  311.                 if (c == '\r' && (ignore_next_return = true) || c == '\n') {
  312.                     // if we receive \r\n, then we only pay attention to \r
  313.                     str = "\r\n";
  314.                 } else {
  315.                     str = Convert.ToString(c);
  316.                 }
  317.  
  318.                 Object[] o = new Object[] { str };
  319.                 edit1.BeginInvoke(new AsyncInvokeStringDelegate(edit1.Append),o);
  320.             }
  321.         }
  322.         catch (Exception e) {
  323.             Console.WriteLine("Client Connection thread: " + e.ToString());
  324.         }
  325.  
  326.         Console.WriteLine("Connection Closed");
  327.  
  328.         DisableClientConnection();
  329.         Console.WriteLine("ClientConnectionThreadProc thread is ending");
  330.     }
  331.     
  332. /*****************************************************************************
  333.  Function:     ServerConnectionThreadProc
  334.  
  335.  Abstract:     Listens on "ServerPort" and creates Socket's for each incoming 
  336.                request.  If ClientConnection is already active, the new 
  337.                Socket is destroyed.
  338.             
  339.  Input Parameters: None
  340.  
  341.  Returns: Void
  342. ******************************************************************************/
  343.     protected void ServerConnectionThreadProc()
  344.     {
  345.         Console.WriteLine("ServerConnectionThread starting");
  346.         try {
  347.             // create server socket and listen on port
  348.             ServerConnection = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
  349.             ServerConnection.Blocking = true;
  350.             if (ServerConnection.Bind(new IPEndPoint(IPAddress.InaddrAny,ServerPort)) != 0) {
  351.                 throw new ApplicationException("Unable to bind to port " + ServerPort.ToString());
  352.             }
  353.  
  354.             ServerConnection.Listen(-1);
  355.             m_ListenStr = "WinTalk listening on port "+ServerPort.ToString();
  356.             Console.WriteLine(m_ListenStr);
  357.             label1.Text = m_ListenStr;
  358.         }
  359.         catch (Exception e) {
  360.             Console.WriteLine("Excpetion: " + e.Message);
  361.             m_ListenStr = "Not listening on any port";
  362.             Console.WriteLine(m_ListenStr);
  363.             label1.Text = m_ListenStr;
  364.             return;
  365.         }
  366.         
  367.         try {
  368.             while (true) {
  369.                 // accept socket requests to our listening port
  370.                 Socket s = ServerConnection.Accept();
  371.                 
  372.                 lock(this) {
  373.                     if (s == null) {
  374.                         throw new ApplicationException("Server connection closed");
  375.                     }
  376.  
  377.                     // if connection already active, reject
  378.                     if (ClientConnection != null) {
  379.                         BeginInvoke(new AsyncInvokeDelegate(this.OnServerReject));
  380.                         String str = "Sorry connection is being rejected....\n";
  381.                         Console.WriteLine(str);
  382.  
  383.                         char[] c = str.ToCharArray();
  384.                         byte[] b = new byte[c.Length];
  385.                         for (int i = 0; i < c.Length; i++) {
  386.                             b[i] = (byte)c[i];
  387.                         }
  388.                         s.Send(b, b.Length, 0);
  389.                         s.Close();
  390.                         continue;
  391.                     }
  392.  
  393.                     // no connection active, make the incoming one our current 
  394.                     // connection
  395.                     ClientConnection = s;
  396.  
  397.                     // notify user that connection has been made
  398.                     BeginInvoke(new AsyncInvokeDelegate(this.OnServerAccept));
  399.  
  400.                     // notify UI thread that connection is active and 
  401.                     // spin off client thread to handle reads from socket
  402.                     EnableClientConnection();
  403.                 }
  404.             }
  405.         }
  406.         catch (Exception e) {
  407.             Console.WriteLine("Server Connection Thread: "+e.ToString());
  408.             if (HandleCreated) {
  409.                 MessageBox.Show(this,"Server Connection: " + e.ToString(),
  410.                         "WinTalk");
  411.             }
  412.             m_ListenStr = "Not listening on any port";
  413.             label1.Text = m_ListenStr;
  414.             if (!bIsInDispose) {
  415.                 Console.WriteLine("Server Connection Thread: "+e.ToString());
  416.                 MessageBox.Show("Server Connection: "+e.ToString(),"WinTalk");
  417.             }
  418.         }
  419.         try {
  420.             if (ServerConnection != null) {
  421.                 ServerConnection.Close();
  422.                 ServerConnection = null;
  423.             }
  424.         }
  425.         catch (Exception e) {
  426.             Console.WriteLine("Server Connection Thread(2): " + e.ToString());
  427.         }
  428.         Console.WriteLine("Server Connection Thread exiting");
  429.     }
  430.         
  431.     
  432. /*****************************************************************************
  433.  Function:     panel1_resize
  434.  
  435.  Abstract:     Invoked when the WFC panel containing the two edit fields
  436.                is resized.  Adjusts the edit boxes to be equal size.
  437.             
  438.  Input Parameters: source(Object), e(EventArgs)
  439.  
  440.  Returns: Void
  441. ******************************************************************************/
  442.     private void panel1_resize(Object source, EventArgs e)
  443.     {
  444.         // Position the splitter in the center of the window
  445.         edit1.Height = (panel1.Height - splitter1.Height) / 2;
  446.     }
  447.  
  448. /*****************************************************************************
  449.  Function:     button1_click
  450.  
  451.  Abstract:     Invoked when the "Connect" button is clicked.  Creates the 
  452.                "ConnectDialog" and enables the client connection.
  453.             
  454.  Input Parameters: source(Object), e(EventArgs)
  455.  
  456.  Returns: Void
  457. ******************************************************************************/
  458.     private void button1_click(Object source, EventArgs e)
  459.     {
  460.         Console.WriteLine("BUTTON1 clicked!!!");
  461.         lock(this) {
  462.             if (ClientConnection != null) {
  463.                 Console.WriteLine("ERROR Connection already is open!!");
  464.                 return;
  465.             }
  466.             ConnectDialog dlg = new ConnectDialog();
  467.             DialogResult ret = dlg.ShowDialog(this);
  468.             if (ret == DialogResult.OK) {
  469.                 try {
  470.                     ClientConnection = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
  471.                     IPAddress host_addr = DNS.Resolve(dlg.host);
  472.                     if (host_addr == null) {
  473.                         throw new ApplicationException("Unable to resolve host "+dlg.host);
  474.                     }
  475.                     IPEndPoint ep = new IPEndPoint(host_addr, dlg.port);
  476.                     if (ClientConnection.Connect(ep) != 0) {
  477.                         throw new ApplicationException("Client connection failed");
  478.                     }
  479.                     EnableClientConnection();
  480.                 }
  481.                 catch (Exception ev) {
  482.                     DisableClientConnection();
  483.                     MessageBox.Show(this,ev.Message,"Connect Error");
  484.                 }
  485.             }
  486.         }
  487.     }
  488.  
  489. /*****************************************************************************
  490.  Function:     button2_click
  491.  
  492.  Abstract:     Invoked when the "Disconnect" button is clicked. Disables the 
  493.                client connection.
  494.             
  495.  Input Parameters: source(Object), e(EventArgs)
  496.  
  497.  Returns: Void
  498. ******************************************************************************/
  499.     private void button2_click(Object source, EventArgs e)
  500.     {
  501.         Console.WriteLine("BUTTON2 clicked!!!");
  502.         DisableClientConnection();        
  503.     }
  504.  
  505. /*****************************************************************************
  506.  Function:     WinTalk_activate
  507.  
  508.  Abstract:     Invoked when the Wintalk application window becomes active.
  509.                Sets focus to the bottom edit control (less confusion to the
  510.                user as to which edit box to type in).
  511.             
  512.  Input Parameters: source(Object), e(EventArgs)
  513.  
  514.  Returns: Void
  515. ******************************************************************************/
  516.     private void WinTalk_activate(Object source, EventArgs e)
  517.     {
  518.         edit2.Focus();
  519.     }
  520.  
  521.     Container components = new Container();
  522.     SendEdit edit2 = new SendEdit();
  523.     DataEdit edit1 = new DataEdit();
  524.     Button button1 = new Button();
  525.     Button button2 = new Button();
  526.     Label label1 = new Label();
  527.     Splitter splitter1 = new Splitter();
  528.     Panel panel1 = new Panel();
  529.  
  530. /*****************************************************************************
  531.  Function:     InitForm
  532.  
  533.  Abstract:     Creates UI elements (buttons, edit controls, ...) on the 
  534.                Wintalk WFC form.
  535.             
  536.  Input Parameters: None
  537.  
  538.  Returns: Void
  539. ******************************************************************************/
  540.     private void InitForm()
  541.     {
  542.         this.Text = "WinTalk";
  543.         this.AutoScaleBaseSize = (Size) new Point(5, 13);
  544.         this.ClientSize = (Size) new Point(406, 344);
  545.         this.AddOnActivate(new EventHandler(this.WinTalk_activate));
  546.  
  547.         edit2.Dock = DockStyle.Fill;
  548.         edit2.Location = new Point(0, 158);
  549.         edit2.Size = (Size) new Point(406, 154);
  550.         edit2.TabIndex = 1;
  551.         edit2.Text = "";
  552.         edit2.Multiline = true;
  553.         edit2.ReadOnly = true;
  554.         edit2.ScrollBars = ScrollBars.Vertical;
  555.         edit2.BackColor = Color.White;
  556.  
  557.         edit1.Dock = DockStyle.Top;
  558.         edit1.Size = (Size) new Point(406, 153);
  559.         edit1.TabIndex = 0;
  560.         edit1.Text = "";
  561.         edit1.Multiline = true;
  562.         edit1.ReadOnly = true;
  563.         edit1.ScrollBars = ScrollBars.Vertical;
  564.         edit1.BackColor = Color.White;
  565.  
  566.         label1.Anchor = AnchorStyles.BottomLeftRight;
  567.         label1.Location = new Point(0, 321);
  568.         label1.Size = (Size) new Point(230, 18);
  569.         label1.TabIndex = 2;
  570.         label1.TabStop = false;
  571.         label1.Text = "";
  572.  
  573.         button1.Anchor = AnchorStyles.BottomRight;
  574.         button1.Location = new Point(331, 317);
  575.         button1.Size = (Size) new Point(72, 24);
  576.         button1.TabIndex = 0;
  577.         button1.Text = "Connect";
  578.         button1.AddOnClick(new EventHandler(this.button1_click));
  579.  
  580.         button2.Anchor = AnchorStyles.BottomRight;
  581.         button2.Enabled = false;
  582.         button2.Location = new Point(235, 317);
  583.         button2.Size = (Size) new Point(88, 24);
  584.         button2.TabIndex = 1;
  585.         button2.Text = "Disconnect";
  586.         button2.AddOnClick(new EventHandler(this.button2_click));
  587.  
  588.         splitter1.Cursor = Cursors.HSplit;
  589.         splitter1.Dock = DockStyle.Top;
  590.         splitter1.Location = new Point(0, 153);
  591.         splitter1.Size = (Size) new Point(406, 5);
  592.         splitter1.TabIndex = 2;
  593.         splitter1.TabStop = false;
  594.  
  595.         panel1.Anchor = AnchorStyles.All;
  596.         panel1.Size = (Size) new Point(406, 312);
  597.         panel1.TabIndex = 3;
  598.         panel1.Text = "panel1";
  599.         panel1.AddOnResize(new EventHandler(this.panel1_resize));
  600.  
  601.         this.Controls.All = new Control[] {
  602.                             panel1, 
  603.                             button2, 
  604.                             button1,
  605.                             label1}; 
  606.         panel1.Controls.All = new Control[] {
  607.                               splitter1, 
  608.                               edit2, 
  609.                               edit1};
  610.     }
  611.  
  612. /*****************************************************************************
  613.  Function:     Main
  614.  
  615.  Abstract:     Entry point into application.
  616.             
  617.  Input Parameters: String[]
  618.  
  619.  Returns: void
  620.  
  621. ******************************************************************************/
  622.     public static void Main(String[] args)
  623.     {
  624.         int port = 5000;
  625.         if (args.Length > 0) {
  626.             try {
  627.                 if (args.Length > 1)
  628.                     throw new ArgumentException();
  629.                 port = Convert.ToInt32(args[0]);
  630.             }
  631.             catch {
  632.                 Console.WriteLine("Usage: Wintalk [port]");
  633.                 return;
  634.             }
  635.         }
  636.         Application.Run(new WinTalk(port));
  637.     }
  638. }
  639.