首先我们了解下关于异步编程的一些知识可以参考我在网上收集的一些资料——C#异步Socket编程
我实现了基于异步通信的Socket服务器和客户端程序
下面是我的代码
第一步:首先新建一个服务端项目YBServerWindowsForms
然后在项目里添加一个自定义的类名为StateObject:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace YBServerWindowsForms
{
class StateObject
{
public Socket WorkSocket = null;
public const int BufferSize = 1024;
public byte[] Buffer = new byte[BufferSize];
public StringBuilder strBuider = new StringBuilder();
public StateObject()
{ }
}
}
接着是界面设计代码ServerForm.Designer.cs
namespace YBServerWindowsForms
{
partial class ServerForm
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.IPTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.PortTextBox = new System.Windows.Forms.TextBox();
this.StartListenButton = new System.Windows.Forms.Button();
this.ReciveMessageRichTextBox = new System.Windows.Forms.RichTextBox();
this.HostStateRichTextBox = new System.Windows.Forms.RichTextBox();
this.label3 = new System.Windows.Forms.Label();
this.StopListenButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// IPTextBox
//
this.IPTextBox.Location = new System.Drawing.Point(81, 41);
this.IPTextBox.Name = "IPTextBox";
this.IPTextBox.Size = new System.Drawing.Size(149, 21);
this.IPTextBox.TabIndex = 0;
this.IPTextBox.Text = "127.0.0.1";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(22, 44);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(41, 12);
this.label1.TabIndex = 1;
this.label1.Text = "主机IP";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(22, 80);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 12);
this.label2.TabIndex = 3;
this.label2.Text = "主机端口";
//
// PortTextBox
//
this.PortTextBox.Location = new System.Drawing.Point(81, 77);
this.PortTextBox.Name = "PortTextBox";
this.PortTextBox.Size = new System.Drawing.Size(149, 21);
this.PortTextBox.TabIndex = 2;
this.PortTextBox.Text = "8080";
//
// StartListenButton
//
this.StartListenButton.Location = new System.Drawing.Point(130, 357);
this.StartListenButton.Name = "StartListenButton";
this.StartListenButton.Size = new System.Drawing.Size(100, 36);
this.StartListenButton.TabIndex = 4;
this.StartListenButton.Text = "开始监听";
this.StartListenButton.UseVisualStyleBackColor = true;
this.StartListenButton.Click += new System.EventHandler(this.StartListenButton_Click);
//
// ReciveMessageRichTextBox
//
this.ReciveMessageRichTextBox.Location = new System.Drawing.Point(24, 131);
this.ReciveMessageRichTextBox.Name = "ReciveMessageRichTextBox";
this.ReciveMessageRichTextBox.Size = new System.Drawing.Size(297, 178);
this.ReciveMessageRichTextBox.TabIndex = 5;
this.ReciveMessageRichTextBox.Text = "";
//
// HostStateRichTextBox
//
this.HostStateRichTextBox.Location = new System.Drawing.Point(335, 56);
this.HostStateRichTextBox.Name = "HostStateRichTextBox";
this.HostStateRichTextBox.Size = new System.Drawing.Size(261, 253);
this.HostStateRichTextBox.TabIndex = 6;
this.HostStateRichTextBox.Text = "";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(333, 41);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(53, 12);
this.label3.TabIndex = 7;
this.label3.Text = "主机状态";
//
// StopListenButton
//
this.StopListenButton.Location = new System.Drawing.Point(335, 357);
this.StopListenButton.Name = "StopListenButton";
this.StopListenButton.Size = new System.Drawing.Size(100, 36);
this.StopListenButton.TabIndex = 8;
this.StopListenButton.Text = "停止监听";
this.StopListenButton.UseVisualStyleBackColor = true;
this.StopListenButton.Click += new System.EventHandler(this.StopListenButton_Click);
//
// ServerForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(631, 430);
this.Controls.Add(this.StopListenButton);
this.Controls.Add(this.label3);
this.Controls.Add(this.HostStateRichTextBox);
this.Controls.Add(this.ReciveMessageRichTextBox);
this.Controls.Add(this.StartListenButton);
this.Controls.Add(this.label2);
this.Controls.Add(this.PortTextBox);
this.Controls.Add(this.label1);
this.Controls.Add(this.IPTextBox);
this.Name = "ServerForm";
this.Text = "YBServerForm";
this.Load += new System.EventHandler(this.ServerForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox IPTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox PortTextBox;
private System.Windows.Forms.Button StartListenButton;
private System.Windows.Forms.RichTextBox ReciveMessageRichTextBox;
private System.Windows.Forms.RichTextBox HostStateRichTextBox;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button StopListenButton;
}
}
主要的逻辑控制代码ServerForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace YBServerWindowsForms
{
public partial class ServerForm : Form
{
private IPAddress ServerIP = IPAddress.Parse("127.0.0.1");//主机地址
private IPEndPoint Server = null;//主机
private int port;//端口
private Socket socket;//套接字
private Socket handler;//接收连接返回的Socket,用以处理接收数据和发送数据
private ManualResetEvent ManReset = new ManualResetEvent(false);//线程同步和异步管理
public ServerForm()
{
InitializeComponent();
}
private void StartListenButton_Click(object sender, EventArgs e)
{
try
{
string strIP = IPTextBox.Text.Trim();
IPHostEntry ServerInfor = Dns.Resolve(strIP);
ServerIP = ServerInfor.AddressList[0];
port = Int32.Parse(PortTextBox.Text.Trim());
}
catch(Exception ex)
{
MessageBox.Show("输入的主机地址格式不正确,请重新输入!");
}
try
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
Server = new IPEndPoint(ServerIP, port);
socket.Bind(Server);
socket.Listen(50);
HostStateRichTextBox.AppendText("主机:" + IPTextBox.Text
+ ",端口:" + port + "开始监听/r/n");
//新建一个线程
Thread thread = new Thread(new ThreadStart(target));
thread.Start();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//线程同步代码
private void target()
{
while(true)
{
ManReset.Reset();//设置没信号等待被阻塞
socket.BeginAccept(new AsyncCallback(AcceptCallback), socket);
ManReset.WaitOne();//阻塞当前线程
}
}
//开始接收的回调函数
private void AcceptCallback(IAsyncResult ar)
{
Socket Listener = (Socket)ar.AsyncState;
handler = Listener.EndAccept(ar);//返回接收连接的Socket用以处理接收数据
ManReset.Set();//设置有信号,通知被阻塞的线程可以运行了
Control.CheckForIllegalCrossThreadCalls = false;//空间可以跨线程访问
HostStateRichTextBox.AppendText("与客户建立连接/r/n");
//新建一个用于接收数据的线程
Thread thread = new Thread(new ThreadStart(BeginRecive));
thread.Start();
}
//接收数据线程同步代码
private void BeginRecive()
{
try
{
StateObject state=new StateObject();
state.WorkSocket = handler;//设置状态信息
handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0,
new AsyncCallback(ReadCallback), state);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//接收数据的回调函数
private void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket ReadSocket = state.WorkSocket;
try
{
int bytes = handler.EndReceive(ar);
state.strBuider.Append(System.Text.Encoding.BigEndianUnicode.GetString(state.Buffer),
0, bytes);
string content = state.strBuider.ToString();
state.strBuider.Remove(0, bytes);
ReciveMessageRichTextBox.AppendText(content + "/r/n");
ReadSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0,
new AsyncCallback(ReadCallback), state);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void StopListenButton_Click(object sender, EventArgs e)
{
try
{
socket.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ServerForm_Load(object sender, EventArgs e)
{
}
}
}
第二步 新建一个客户端项目名称为YBClientWindowsForms
下面是界面设计YBClientForm.Designer.cs:
namespace YBClientWindowsForms
{
partial class YBClientForm
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.label2 = new System.Windows.Forms.Label();
this.PortTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.IPTextBox = new System.Windows.Forms.TextBox();
this.ConnectButton = new System.Windows.Forms.Button();
this.SendRichTextBox = new System.Windows.Forms.RichTextBox();
this.label3 = new System.Windows.Forms.Label();
this.SendButton = new System.Windows.Forms.Button();
this.ConnectStateTextBox = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.CloseButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(41, 83);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 12);
this.label2.TabIndex = 7;
this.label2.Text = "主机端口";
//
// PortTextBox
//
this.PortTextBox.Location = new System.Drawing.Point(100, 80);
this.PortTextBox.Name = "PortTextBox";
this.PortTextBox.Size = new System.Drawing.Size(149, 21);
this.PortTextBox.TabIndex = 6;
this.PortTextBox.Text = "8080";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(41, 47);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(41, 12);
this.label1.TabIndex = 5;
this.label1.Text = "主机IP";
//
// IPTextBox
//
this.IPTextBox.Location = new System.Drawing.Point(100, 44);
this.IPTextBox.Name = "IPTextBox";
this.IPTextBox.Size = new System.Drawing.Size(149, 21);
this.IPTextBox.TabIndex = 4;
this.IPTextBox.Text = "127.0.0.1";
//
// ConnectButton
//
this.ConnectButton.Location = new System.Drawing.Point(287, 47);
this.ConnectButton.Name = "ConnectButton";
this.ConnectButton.Size = new System.Drawing.Size(90, 40);
this.ConnectButton.TabIndex = 8;
this.ConnectButton.Text = "连接";
this.ConnectButton.UseVisualStyleBackColor = true;
this.ConnectButton.Click += new System.EventHandler(this.ConnectButton_Click);
//
// SendRichTextBox
//
this.SendRichTextBox.Location = new System.Drawing.Point(100, 167);
this.SendRichTextBox.Name = "SendRichTextBox";
this.SendRichTextBox.Size = new System.Drawing.Size(344, 109);
this.SendRichTextBox.TabIndex = 9;
this.SendRichTextBox.Text = "";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(41, 170);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(53, 12);
this.label3.TabIndex = 10;
this.label3.Text = "发送信息";
//
// SendButton
//
this.SendButton.Location = new System.Drawing.Point(168, 294);
this.SendButton.Name = "SendButton";
this.SendButton.Size = new System.Drawing.Size(169, 55);
this.SendButton.TabIndex = 11;
this.SendButton.Text = "发送";
this.SendButton.UseVisualStyleBackColor = true;
this.SendButton.Click += new System.EventHandler(this.SendButton_Click);
//
// ConnectStateTextBox
//
this.ConnectStateTextBox.Location = new System.Drawing.Point(100, 124);
this.ConnectStateTextBox.Name = "ConnectStateTextBox";
this.ConnectStateTextBox.Size = new System.Drawing.Size(344, 21);
this.ConnectStateTextBox.TabIndex = 12;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(41, 127);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(53, 12);
this.label4.TabIndex = 13;
this.label4.Text = "连接状态";
//
// CloseButton
//
this.CloseButton.Location = new System.Drawing.Point(402, 47);
this.CloseButton.Name = "CloseButton";
this.CloseButton.Size = new System.Drawing.Size(90, 40);
this.CloseButton.TabIndex = 14;
this.CloseButton.Text = "断开";
this.CloseButton.UseVisualStyleBackColor = true;
this.CloseButton.Click += new System.EventHandler(this.CloseButton_Click);
//
// YBClientForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(517, 371);
this.Controls.Add(this.CloseButton);
this.Controls.Add(this.label4);
this.Controls.Add(this.ConnectStateTextBox);
this.Controls.Add(this.SendButton);
this.Controls.Add(this.label3);
this.Controls.Add(this.SendRichTextBox);
this.Controls.Add(this.ConnectButton);
this.Controls.Add(this.label2);
this.Controls.Add(this.PortTextBox);
this.Controls.Add(this.label1);
this.Controls.Add(this.IPTextBox);
this.Name = "YBClientForm";
this.Text = "YBClientForm";
this.Load += new System.EventHandler(this.YBClientForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox PortTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox IPTextBox;
private System.Windows.Forms.Button ConnectButton;
private System.Windows.Forms.RichTextBox SendRichTextBox;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button SendButton;
private System.Windows.Forms.TextBox ConnectStateTextBox;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Button CloseButton;
}
}
主要的逻辑控制代码YBClientForm.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace YBClientWindowsForms
{
public partial class YBClientForm : Form
{
private IPAddress ServerIP = IPAddress.Parse("127.0.0.1");//地址
private IPEndPoint ServerEP = null;//远程主机
private int port;//远程主机端口号
private Socket handler;//句柄
public YBClientForm()
{
InitializeComponent();
}
private void ConnectButton_Click(object sender, EventArgs e)
{
try
{
string strIP = IPTextBox.Text.Trim();
IPHostEntry ServerInfor = Dns.Resolve(strIP);
ServerIP = ServerInfor.AddressList[0];
port = Int32.Parse(PortTextBox.Text.Trim());
}
catch(Exception ex)
{
MessageBox.Show("输入的主机地址格式不正确,请重新输入!");
}
try
{
handler = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
ServerEP = new IPEndPoint(ServerIP,port);
handler.BeginConnect(ServerEP,new AsyncCallback(ConnectCallback),handler);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//连接回调函数
private void ConnectCallback(IAsyncResult ar)
{
Socket ConnSocket = (Socket)ar.AsyncState;
Control.CheckForIllegalCrossThreadCalls = false;
ConnectStateTextBox.Text = "已经连接上主机";
handler.EndConnect(ar);
}
private void SendButton_Click(object sender, EventArgs e)
{
try
{
string strSend = SendRichTextBox.Text.Trim();
if(strSend.Equals(""))
{
MessageBox.Show("发送信息不能为空");
return;
}
byte[] sendbytes =System.Text.Encoding.BigEndianUnicode.GetBytes(strSend.ToCharArray());
handler.BeginSend(sendbytes,0,sendbytes.Length,0,
new AsyncCallback(SendCallback),handler);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
int sendbytes = handler.EndSend(ar);
//MessageBox.Show("以发送了" + sendbytes + "个字节");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void YBClientForm_Load(object sender, EventArgs e)
{
}
private void CloseButton_Click(object sender, EventArgs e)
{
try
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
ConnectStateTextBox.Text = "与主机断开连接!";
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
本程序在Windows 7 下用VS2008调试通过