/* NotifyCommand enum -- List of socket notification commands. ClientSocket class -- Connects and sends data over TCP sockets. Uses async sockets so a delegate method is called when the socket command completes. Raises an Notify event when socket operations complete and passes any associated data with the event. */ using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; using System.Text; using System.Configuration; using System.Collections; using System.Diagnostics; using Common; namespace PocketSignature { /// /// Socket notification commands. /// public enum NotifyCommand { Connected, SentData, ReceivedData, Error } /// /// Use async sockets to connect, send and receive data over TCP sockets. /// public class ClientSocket { // notification event public delegate void NotifyEventHandler(NotifyCommand command, object data); public event NotifyEventHandler Notify; // socket that exchanges information with server Socket _socket; // holds information sent back from server byte[] _readBuffer = new byte[1]; // used to synchronize the shutdown process, terminate // any pending async calls before Disconnect returns ManualResetEvent _asyncEvent = new ManualResetEvent(true); bool _disconnecting = false; // async callbacks AsyncCallback _connectCallback, _sendCallback, _receiveCallback; /// /// Returns true if the socket is connected to the server. The property /// Socket.Connected does not always indicate if the socket is currently /// connected, this polls the socket to determine the latest connection state. /// public bool Connected { get { // return right away if have not created socket if (_socket == null) return false; // the socket is not connected if the Connected property is false if (!_socket.Connected) return false; // there is no guarantee that the socket is connected even if the // Connected property is true try { // poll for error to see if socket is connected return !_socket.Poll(1, SelectMode.SelectError); } catch { return false; } } } public ClientSocket() { // hookup async callbacks _connectCallback = new AsyncCallback(ConnectCallback); _sendCallback = new AsyncCallback(SendCallback); _receiveCallback = new AsyncCallback(ReceiveCallback); } /// /// Connect to the specified address and port number. /// public void Connect(string address, int port) { // make sure disconnected Disconnect(); // connect to the server IPAddress ipAddress = IPAddress.Parse(address); IPEndPoint endPoint = new IPEndPoint(ipAddress, port); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _asyncEvent.Reset(); _socket.BeginConnect(endPoint, _connectCallback, null); } /// /// Disconnect from the server. /// public void Disconnect() { // return right away if have not created socket if (_socket == null) return; // set this flag so we don't raise any error notification // events when disconnecting _disconnecting = true; try { // first, shutdown the socket _socket.Shutdown(SocketShutdown.Both); } catch {} try { // next, close the socket which terminates any pending // async operations _socket.Close(); // wait for any async operations to complete _asyncEvent.WaitOne(); } catch {} _disconnecting = false; } /// /// Send data to the server. /// public void Send(byte[] data) { // send the data _socket.BeginSend(data, 0, data.Length, SocketFlags.None, null, null); // send the terminator _asyncEvent.Reset(); _socket.BeginSend(Network.TerminatorBytes, 0, Network.TerminatorBytes.Length, SocketFlags.None, _sendCallback, true); } /// /// Read data from server. /// public void Receive() { _asyncEvent.Reset(); _socket.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, _receiveCallback, null); } /// /// Raise notification event. /// private void RaiseNotifyEvent(NotifyCommand command, object data) { // the async operation has completed _asyncEvent.Set(); // don't raise notification events when disconnecting if ((this.Notify != null) && !_disconnecting) Notify(command, data); } // // async callbacks // private void ConnectCallback(IAsyncResult ar) { try { // pass connection status with event _socket.EndConnect(ar); RaiseNotifyEvent(NotifyCommand.Connected, this.Connected); } catch (Exception ex) { RaiseNotifyEvent(NotifyCommand.Error, ex.Message); } } private void SendCallback(IAsyncResult ar) { try { _socket.EndSend(ar); RaiseNotifyEvent(NotifyCommand.SentData, null); } catch (Exception ex) { RaiseNotifyEvent(NotifyCommand.Error, ex.Message); } } private void ReceiveCallback(IAsyncResult ar) { try { _socket.EndReceive(ar); // the server sends an acknowledgment back // that is stored in the read buffer RaiseNotifyEvent(NotifyCommand.ReceivedData, _readBuffer[0] == 1 ? true : false); } catch (Exception ex) { RaiseNotifyEvent(NotifyCommand.Error, ex.Message); } } } }