C#聊天程式 (轉)

worldblog發表於2007-12-10
C#聊天程式 (轉)[@more@]

/*=====================================================================
  :  Wintalk.cs

  摘要:  演示如何使用建立

=====================================================================*/

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Drawing;
using System..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
  Talker talker = new Talker(endPoint, client);
  // Pass the object reference to a new foobject
  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(.Resolve(address).Addreist[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...]nn"+
  "  /L  [port]tt-- Listens on a port.  Default:  5150n"+
  "  /C  [address] [port]t-- Connects to an address and port.nn"+
  "Example Server - n"+
  "Wintalk /Lnn"+
  "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.Wrap = 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 overr 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.ionStart = 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 res and surpress finalization
  public void Dispose(){ 
  GC.Suppresinalize(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 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[] commanuffer = 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; 
}

.NET SDK帶這個例子.


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990752/,如需轉載,請註明出處,否則將追究法律責任。

相關文章