home *** CD-ROM | disk | FTP | other *** search
- /*+==========================================================================
- File: wintalk.cs
-
- Summary: This contains the front-end logic to wintalk, and entry point.
- This application demonstrates the use of WFC and System.Net.DLL.
-
- Wintalk starts with a dialog that with to multi-line edit boxes
- and two buttons (one grayed out). In the background, it spins
- off a thread (ServerConnectionThread) which begins listening on
- TCP/IP port 5000. When an incoming connection arrives, the
- ServerConnectionThread posts a message to the UI thread to
- un-gray the "disconnect" button, and gray out the "connect"
- button, and a client thread is started which receive all data
- and sends the characters to the top edit window. The user types
- in the bottom edit window to transmit to the remote end.
-
- WFC's InvokeAsync is used to provide a thread switch from one
- of the "worker" threads (such as ServerConnectionThread) to
- the UI thread (which is started from Main, and messages pumped
- in Application.Run).
-
- Classes: Wintalk
-
- Functions:
- Overrides: Dispose
-
- Initialization: InitForm
-
- Thread procedures: ClientConnectionThreadProc,
- ServerConnectionThreadProc
-
- Async Invoked Methods: OnClientActive, OnClientClosed,
- OnServerAccept, OnServerReject
-
- Other: EnableClientConnection,
- DisableClientConnection
-
- UI Event Handlers: panel1_resize, button1_click,
- button2_click, WinTalk_activate
-
- Entry point: Main
-
- ----------------------------------------------------------------------------
- This file is part of the Microsoft NGWS Samples.
-
- Copyright (C) 1998-2000 Microsoft Corporation. All rights reserved.
- ==========================================================================+*/
-
- using System;
- using System.Threading;
- using System.ComponentModel;
- using System.Core;
- using System.WinForms;
- using System.Runtime.InteropServices;
- using System.Drawing;
- using System.Net;
- using System.Net.Sockets;
-
- // define delegates to be used with AsyncInvoke
- delegate void AsyncInvokeDelegate();
- delegate void AsyncInvokeStringDelegate(String str);
-
-
- public class WinTalk : Form
- {
- protected Socket ClientConnection = null;
- protected Socket ServerConnection = null;
-
- public int ServerPort = 5000;
-
- protected Thread ClientConnectionThread = null;
- protected Thread ServerConnectionThread = null;
-
- protected String m_ListenStr;
-
- protected bool bIsInDispose = false;
-
- /*****************************************************************************
- Constructor : WinTalk
-
- Abstract: Constructs an instance of Wintalk, calls Window's default
- contructor.
-
- Input Parameters: port(int)
-
- ******************************************************************************/
- public WinTalk(int port)
- {
- this.ServerPort = port;
-
- InitForm();
-
- // start "Listening" thread
- ServerConnectionThread = new Thread(new ThreadStart(this.ServerConnectionThreadProc));
- ServerConnectionThread.Start();
- }
-
- /*****************************************************************************
- Function: Dispose
-
- Abstract: Overrides Form.Dispose, cleans up the component list.
-
- Input Parameters: (None)
-
- Returns: void
- ******************************************************************************/
- public override void Dispose()
- {
- bIsInDispose = true;
- base.Dispose();
- components.Dispose();
-
- DisableClientConnection();
-
- // Kill server thread
- try {
- if (ServerConnection != null)
- ServerConnection.Close();
- }
- catch
- {
- Console.WriteLine("Error while closing server connection!!!!!");
- }
- ServerConnection = null;
-
- if (ServerConnectionThread != null)
- ServerConnectionThread.Join();
- ServerConnectionThread = null;
-
- if (ClientConnectionThread != null)
- ClientConnectionThread.Join();
- ClientConnectionThread = null;
- }
-
- /*****************************************************************************
- Function: OnClientActive
-
- Abstract: Invoked asynchronously when a connection becomes active.
-
- Input Parameters: (None)
-
- Returns: void
- ******************************************************************************/
- protected void OnClientActive()
- {
- button1.Enabled = false;
- button2.Enabled = true;
- edit2.Focus(); // helps to eliminate confusion, sets focus to SendEdit
-
- IPEndPoint ep = (IPEndPoint)ClientConnection.RemoteEndpoint;
-
- String addr = DNS.InetNtoa(ep.Address);
- int port = ep.Port;
- String host = DNS.GetHostByAddr(addr).Hostname;
- String s = "Talking to "+addr+":"+port.ToString()+"("+host+")";
- Console.WriteLine(s);
- label1.Text = s;
- }
-
- /*****************************************************************************
- Function: OnClientClosed
-
- Abstract: Invoked asynchronously when the active connection is closed
-
- Input Parameters: (None)
-
- Returns: void
- ******************************************************************************/
- protected void OnClientClosed()
- {
- edit1.Append("\r\n****Notice: Connection Closed****\r\n");
- button1.Enabled = true;
- button2.Enabled = false;
- label1.Text = m_ListenStr;
- }
-
- /*****************************************************************************
- Function: OnServerAccept
-
- Abstract: Invoked asynchronously when an incoming connection is accepted
- by the server thread.
-
- Input Parameters: (None)
-
- Returns: void
- ******************************************************************************/
- protected void OnServerAccept()
- {
- edit1.Append("\r\n****CONNECTION ACTIVE****\r\n");
- WindowState = FormWindowState.Normal;
- //Windows.SetForegroundWindow(Handle);
- }
-
- /*****************************************************************************
- Function: OnServerReject
-
- Abstract: Invoked asynchronously when an incoming connection is rejected
- by the server thread.
-
- Input Parameters: (None)
-
- Returns: void
- ******************************************************************************/
- protected void OnServerReject()
- {
- edit1.Append("\r\n****Warning: Incoming being rejected****\r\n");
- }
-
- /*****************************************************************************
- Function: EnableClientConnection
-
- Abstract: Called when "ClientConnection" becomes valid. Resets UI to
- proper state and spins off a ClientConnectionThread thread.
-
- Input Parameters: None
-
- Returns: Void
- ******************************************************************************/
- public void EnableClientConnection()
- {
- if (ClientConnectionThread != null) {
- throw new ApplicationException("Client reader thread "+
- "(ClientConnectionThread) already "+
- "active!!");
- }
- ClientConnectionThread = new Thread(new ThreadStart(this.ClientConnectionThreadProc));
- ClientConnectionThread.Start();
- BeginInvoke(new AsyncInvokeDelegate(this.OnClientActive));
- edit2.SetClientConnection(ClientConnection);
- }
-
- /*****************************************************************************
- Function: DisableClientConnection
-
- Abstract: Called when "ClientConnection" becomes invalid, or actually
- closes ClientConnection. Resets UI to proper state and if not
- called from ClientConnectionThread, waits for this thread to
- terminate.
-
- Input Parameters: None
-
- Returns: Void
- ******************************************************************************/
- public void DisableClientConnection()
- {
- try {
- edit2.SetClientConnection(null);
- lock(this) {
- if (ClientConnection != null) {
- Console.WriteLine("DisableClientConnection: "+
- "closing connection");
- ClientConnection.Close();
- ClientConnection = null;
- }
- }
- }
- catch (Exception e) {
- MessageBox.Show(this,e.Message,"Close Error");
- }
- if (Thread.CurrentThread == ClientConnectionThread) {
- ClientConnectionThread = null;
- if (this.HandleCreated) {
- BeginInvoke(new AsyncInvokeDelegate(this.OnClientClosed));
- }
- } else {
- if (ClientConnectionThread != null) {
- ClientConnectionThread.Join();
- ClientConnectionThread = null;
- }
- }
- }
-
- /*****************************************************************************
- Function: ClientConnectionThreadProc
-
- Abstract: Called when a client connection is made (click the "connect"
- button, or incoming connection is made). This thread is
- created and started from the "EnableClientConnection" method.
-
- Input Parameters: None
-
- Returns: Void
- ******************************************************************************/
- protected void ClientConnectionThreadProc()
- {
- Console.WriteLine("ClientConnectionThreadProc thread is starting");
- try {
- char c = '\0';
-
- bool ignore_next_return = false;
- byte[] b = new byte[1];
-
- // read one character at a time from the Socket
- while (ClientConnection != null && ClientConnection.Receive(b,b.Length,0) > 0) {
- c = (char)b[0];
- if (ignore_next_return && (c == '\r' || c == '\n')) {
- ignore_next_return = false;
- continue;
- }
- ignore_next_return = false;
-
- if (c == '\b') {
- // backspace character causes use to truncate one char
- // off of the edit control
- edit1.BeginInvoke(new AsyncInvokeDelegate(edit1.TruncateOneCharFromEnd));
- continue;
- }
-
- String str = null;
-
- if (c == '\r' && (ignore_next_return = true) || c == '\n') {
- // if we receive \r\n, then we only pay attention to \r
- str = "\r\n";
- } else {
- str = Convert.ToString(c);
- }
-
- Object[] o = new Object[] { str };
- edit1.BeginInvoke(new AsyncInvokeStringDelegate(edit1.Append),o);
- }
- }
- catch (Exception e) {
- Console.WriteLine("Client Connection thread: " + e.ToString());
- }
-
- Console.WriteLine("Connection Closed");
-
- DisableClientConnection();
- Console.WriteLine("ClientConnectionThreadProc thread is ending");
- }
-
- /*****************************************************************************
- Function: ServerConnectionThreadProc
-
- Abstract: Listens on "ServerPort" and creates Socket's for each incoming
- request. If ClientConnection is already active, the new
- Socket is destroyed.
-
- Input Parameters: None
-
- Returns: Void
- ******************************************************************************/
- protected void ServerConnectionThreadProc()
- {
- Console.WriteLine("ServerConnectionThread starting");
- try {
- // create server socket and listen on port
- ServerConnection = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
- ServerConnection.Blocking = true;
- if (ServerConnection.Bind(new IPEndPoint(IPAddress.InaddrAny,ServerPort)) != 0) {
- throw new ApplicationException("Unable to bind to port " + ServerPort.ToString());
- }
-
- ServerConnection.Listen(-1);
- m_ListenStr = "WinTalk listening on port "+ServerPort.ToString();
- Console.WriteLine(m_ListenStr);
- label1.Text = m_ListenStr;
- }
- catch (Exception e) {
- Console.WriteLine("Excpetion: " + e.Message);
- m_ListenStr = "Not listening on any port";
- Console.WriteLine(m_ListenStr);
- label1.Text = m_ListenStr;
- return;
- }
-
- try {
- while (true) {
- // accept socket requests to our listening port
- Socket s = ServerConnection.Accept();
-
- lock(this) {
- if (s == null) {
- throw new ApplicationException("Server connection closed");
- }
-
- // if connection already active, reject
- if (ClientConnection != null) {
- BeginInvoke(new AsyncInvokeDelegate(this.OnServerReject));
- String str = "Sorry connection is being rejected....\n";
- Console.WriteLine(str);
-
- char[] c = str.ToCharArray();
- byte[] b = new byte[c.Length];
- for (int i = 0; i < c.Length; i++) {
- b[i] = (byte)c[i];
- }
- s.Send(b, b.Length, 0);
- s.Close();
- continue;
- }
-
- // no connection active, make the incoming one our current
- // connection
- ClientConnection = s;
-
- // notify user that connection has been made
- BeginInvoke(new AsyncInvokeDelegate(this.OnServerAccept));
-
- // notify UI thread that connection is active and
- // spin off client thread to handle reads from socket
- EnableClientConnection();
- }
- }
- }
- catch (Exception e) {
- Console.WriteLine("Server Connection Thread: "+e.ToString());
- if (HandleCreated) {
- MessageBox.Show(this,"Server Connection: " + e.ToString(),
- "WinTalk");
- }
- m_ListenStr = "Not listening on any port";
- label1.Text = m_ListenStr;
- if (!bIsInDispose) {
- Console.WriteLine("Server Connection Thread: "+e.ToString());
- MessageBox.Show("Server Connection: "+e.ToString(),"WinTalk");
- }
- }
- try {
- if (ServerConnection != null) {
- ServerConnection.Close();
- ServerConnection = null;
- }
- }
- catch (Exception e) {
- Console.WriteLine("Server Connection Thread(2): " + e.ToString());
- }
- Console.WriteLine("Server Connection Thread exiting");
- }
-
-
- /*****************************************************************************
- Function: panel1_resize
-
- Abstract: Invoked when the WFC panel containing the two edit fields
- is resized. Adjusts the edit boxes to be equal size.
-
- Input Parameters: source(Object), e(EventArgs)
-
- Returns: Void
- ******************************************************************************/
- private void panel1_resize(Object source, EventArgs e)
- {
- // Position the splitter in the center of the window
- edit1.Height = (panel1.Height - splitter1.Height) / 2;
- }
-
- /*****************************************************************************
- Function: button1_click
-
- Abstract: Invoked when the "Connect" button is clicked. Creates the
- "ConnectDialog" and enables the client connection.
-
- Input Parameters: source(Object), e(EventArgs)
-
- Returns: Void
- ******************************************************************************/
- private void button1_click(Object source, EventArgs e)
- {
- Console.WriteLine("BUTTON1 clicked!!!");
- lock(this) {
- if (ClientConnection != null) {
- Console.WriteLine("ERROR Connection already is open!!");
- return;
- }
- ConnectDialog dlg = new ConnectDialog();
- DialogResult ret = dlg.ShowDialog(this);
- if (ret == DialogResult.OK) {
- try {
- ClientConnection = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
- IPAddress host_addr = DNS.Resolve(dlg.host);
- if (host_addr == null) {
- throw new ApplicationException("Unable to resolve host "+dlg.host);
- }
- IPEndPoint ep = new IPEndPoint(host_addr, dlg.port);
- if (ClientConnection.Connect(ep) != 0) {
- throw new ApplicationException("Client connection failed");
- }
- EnableClientConnection();
- }
- catch (Exception ev) {
- DisableClientConnection();
- MessageBox.Show(this,ev.Message,"Connect Error");
- }
- }
- }
- }
-
- /*****************************************************************************
- Function: button2_click
-
- Abstract: Invoked when the "Disconnect" button is clicked. Disables the
- client connection.
-
- Input Parameters: source(Object), e(EventArgs)
-
- Returns: Void
- ******************************************************************************/
- private void button2_click(Object source, EventArgs e)
- {
- Console.WriteLine("BUTTON2 clicked!!!");
- DisableClientConnection();
- }
-
- /*****************************************************************************
- Function: WinTalk_activate
-
- Abstract: Invoked when the Wintalk application window becomes active.
- Sets focus to the bottom edit control (less confusion to the
- user as to which edit box to type in).
-
- Input Parameters: source(Object), e(EventArgs)
-
- Returns: Void
- ******************************************************************************/
- private void WinTalk_activate(Object source, EventArgs e)
- {
- edit2.Focus();
- }
-
- Container components = new Container();
- SendEdit edit2 = new SendEdit();
- DataEdit edit1 = new DataEdit();
- Button button1 = new Button();
- Button button2 = new Button();
- Label label1 = new Label();
- Splitter splitter1 = new Splitter();
- Panel panel1 = new Panel();
-
- /*****************************************************************************
- Function: InitForm
-
- Abstract: Creates UI elements (buttons, edit controls, ...) on the
- Wintalk WFC form.
-
- Input Parameters: None
-
- Returns: Void
- ******************************************************************************/
- private void InitForm()
- {
- this.Text = "WinTalk";
- this.AutoScaleBaseSize = (Size) new Point(5, 13);
- this.ClientSize = (Size) new Point(406, 344);
- this.AddOnActivate(new EventHandler(this.WinTalk_activate));
-
- edit2.Dock = DockStyle.Fill;
- edit2.Location = new Point(0, 158);
- edit2.Size = (Size) new Point(406, 154);
- edit2.TabIndex = 1;
- edit2.Text = "";
- edit2.Multiline = true;
- edit2.ReadOnly = true;
- edit2.ScrollBars = ScrollBars.Vertical;
- edit2.BackColor = Color.White;
-
- edit1.Dock = DockStyle.Top;
- edit1.Size = (Size) new Point(406, 153);
- edit1.TabIndex = 0;
- edit1.Text = "";
- edit1.Multiline = true;
- edit1.ReadOnly = true;
- edit1.ScrollBars = ScrollBars.Vertical;
- edit1.BackColor = Color.White;
-
- label1.Anchor = AnchorStyles.BottomLeftRight;
- label1.Location = new Point(0, 321);
- label1.Size = (Size) new Point(230, 18);
- label1.TabIndex = 2;
- label1.TabStop = false;
- label1.Text = "";
-
- button1.Anchor = AnchorStyles.BottomRight;
- button1.Location = new Point(331, 317);
- button1.Size = (Size) new Point(72, 24);
- button1.TabIndex = 0;
- button1.Text = "Connect";
- button1.AddOnClick(new EventHandler(this.button1_click));
-
- button2.Anchor = AnchorStyles.BottomRight;
- button2.Enabled = false;
- button2.Location = new Point(235, 317);
- button2.Size = (Size) new Point(88, 24);
- button2.TabIndex = 1;
- button2.Text = "Disconnect";
- button2.AddOnClick(new EventHandler(this.button2_click));
-
- splitter1.Cursor = Cursors.HSplit;
- splitter1.Dock = DockStyle.Top;
- splitter1.Location = new Point(0, 153);
- splitter1.Size = (Size) new Point(406, 5);
- splitter1.TabIndex = 2;
- splitter1.TabStop = false;
-
- panel1.Anchor = AnchorStyles.All;
- panel1.Size = (Size) new Point(406, 312);
- panel1.TabIndex = 3;
- panel1.Text = "panel1";
- panel1.AddOnResize(new EventHandler(this.panel1_resize));
-
- this.Controls.All = new Control[] {
- panel1,
- button2,
- button1,
- label1};
- panel1.Controls.All = new Control[] {
- splitter1,
- edit2,
- edit1};
- }
-
- /*****************************************************************************
- Function: Main
-
- Abstract: Entry point into application.
-
- Input Parameters: String[]
-
- Returns: void
-
- ******************************************************************************/
- public static void Main(String[] args)
- {
- int port = 5000;
- if (args.Length > 0) {
- try {
- if (args.Length > 1)
- throw new ArgumentException();
- port = Convert.ToInt32(args[0]);
- }
- catch {
- Console.WriteLine("Usage: Wintalk [port]");
- return;
- }
- }
- Application.Run(new WinTalk(port));
- }
- }
-