MSDN 上也有个关于 Socket 通信的简单例子。我这是从那上面搬过来的。不过改来改去就变得跟原来的差得不少了。我觉得比 MSDN 上的例子会更好一点。因为可以自己定义要传送的数据类型,只要要传送的数据是可以序列化的。
我把程序分成两大块:PostOffice,Package。PostOffice 实现收发功能,相当于邮局。Package 包含了这个包的类型和包里面要传送的数据。
Package 类的定义:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace TalkDemo.Core
{
[Serializable]
public class Package
{
private PackageType packageType;
public PackageType PackageType
{
get { return packageType; }
}
private IPEndPoint sourceEP;
public IPEndPoint SourceEP
{
get { return sourceEP; }
}
private IPEndPoint destEP;
public IPEndPoint DestEP
{
get { return destEP; }
}
private object[] data;
public object[] Data
{
get { return data; }
}
public Package(PackageType packageType, IPEndPoint sourceEP, IPEndPoint destEP,
params object[] data)
{
this.packageType = packageType;
this.sourceEP = sourceEP;
this.destEP = destEP;
this.data = data;
}
public static void Serialize(Stream stream, Package package)
{
if (package == null) return;
if (stream == null) return;
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(stream, package);
}
public static Package Deserialize(Stream stream)
{
if (stream == null) return null;
BinaryFormatter binFormatter = new BinaryFormatter();
Package package;
try
{
package = binFormatter.Deserialize(stream) as Package;
}
catch
{
return null;
}
return package;
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace TalkDemo.Core
{
[Serializable]
public class Package
{
private PackageType packageType;
public PackageType PackageType
{
get { return packageType; }
}
private IPEndPoint sourceEP;
public IPEndPoint SourceEP
{
get { return sourceEP; }
}
private IPEndPoint destEP;
public IPEndPoint DestEP
{
get { return destEP; }
}
private object[] data;
public object[] Data
{
get { return data; }
}
public Package(PackageType packageType, IPEndPoint sourceEP, IPEndPoint destEP,
params object[] data)
{
this.packageType = packageType;
this.sourceEP = sourceEP;
this.destEP = destEP;
this.data = data;
}
public static void Serialize(Stream stream, Package package)
{
if (package == null) return;
if (stream == null) return;
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(stream, package);
}
public static Package Deserialize(Stream stream)
{
if (stream == null) return null;
BinaryFormatter binFormatter = new BinaryFormatter();
Package package;
try
{
package = binFormatter.Deserialize(stream) as Package;
}
catch
{
return null;
}
return package;
}
}
}
PackageType 枚举的定义:
namespace TalkDemo.Core
{
public enum PackageType
{
Data,
ExitSignal,
}
}
{
public enum PackageType
{
Data,
ExitSignal,
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace TalkDemo.Core
{
public class PackageReceivedEventArgs
: EventArgs
{
private Package package;
public Package Package
{
get { return package; }
}
public PackageReceivedEventArgs(Package package)
{
this.package = package;
}
}
}
namespace TalkDemo.Core
{
public delegate void PackageReceivedEventhandler(object sender, PackageReceivedEventArgs e);
}
using System.Collections.Generic;
using System.Text;
namespace TalkDemo.Core
{
public class PackageReceivedEventArgs
: EventArgs
{
private Package package;
public Package Package
{
get { return package; }
}
public PackageReceivedEventArgs(Package package)
{
this.package = package;
}
}
}
namespace TalkDemo.Core
{
public delegate void PackageReceivedEventhandler(object sender, PackageReceivedEventArgs e);
}
PostOffice 的定义:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Threading;
namespace TalkDemo.Core
{
public sealed class PostOffice
{
Fields
Properties
Methods
Enumerations
Events
private class AcceptCallArgs
{
private Socket socket;
public Socket Socket
{
get { return socket; }
}
private ListenAs role;
public ListenAs Role
{
get { return role; }
}
public AcceptCallArgs(Socket socket, ListenAs role)
{
this.socket = socket;
this.role = role;
}
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Threading;
namespace TalkDemo.Core
{
public sealed class PostOffice
{
Fields
Properties
Methods
Enumerations
Events
private class AcceptCallArgs
{
private Socket socket;
public Socket Socket
{
get { return socket; }
}
private ListenAs role;
public ListenAs Role
{
get { return role; }
}
public AcceptCallArgs(Socket socket, ListenAs role)
{
this.socket = socket;
this.role = role;
}
}
}
}
可以看出来,这里发送是同步的,但接收是异步的。这个程序也算是个怪胎了!@#@#¥#,不过全当练习了。
有了这个通信的核心,就可以做个简单的双向通信程序了。
using System;
using System.Collections.Generic;
using System.Text;
using TalkDemo.Core;
using System.Net;
namespace TalkTest.Ui
{
class Program
{
static void Main(string[] args)
{
PostOffice postOffice = PostOffice.Instance;
try
{
Console.Write("Target ip: ");
string targetIp = Console.ReadLine();
IPHostEntry targetEntry = Dns.GetHostEntry(targetIp);
IPEndPoint targetEP = new IPEndPoint(targetEntry.AddressList[0], PostOffice.ClientPort);
postOffice.PackageReceived += new PackageReceivedEventhandler(postOffice_PackageReceived);
postOffice.BeginListen(PostOffice.ListenAs.Client);
Console.Write("Talk Demo> ");
string input = Console.ReadLine();
while (!input.ToLower().Equals("exit"))
{
Package p = new Package(PackageType.Data, postOffice.LocalClientEP, targetEP, input);
try
{
postOffice.Send(p);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Write("Talk Demo> ");
input = Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
postOffice.EndListen(PostOffice.ListenAs.Client);
}
Console.WriteLine("Press any key to continue");
Console.ReadKey(true);
}
static void postOffice_PackageReceived(object sender, PackageReceivedEventArgs e)
{
if (e.Package.PackageType == PackageType.Data)
{
Console.WriteLine("\r\nFrom [" + e.Package.SourceEP.Address.ToString() + "]> " + e.Package.Data[0].ToString());
Console.Write("Talk Demo> ");
}
}
}
}
using System.Collections.Generic;
using System.Text;
using TalkDemo.Core;
using System.Net;
namespace TalkTest.Ui
{
class Program
{
static void Main(string[] args)
{
PostOffice postOffice = PostOffice.Instance;
try
{
Console.Write("Target ip: ");
string targetIp = Console.ReadLine();
IPHostEntry targetEntry = Dns.GetHostEntry(targetIp);
IPEndPoint targetEP = new IPEndPoint(targetEntry.AddressList[0], PostOffice.ClientPort);
postOffice.PackageReceived += new PackageReceivedEventhandler(postOffice_PackageReceived);
postOffice.BeginListen(PostOffice.ListenAs.Client);
Console.Write("Talk Demo> ");
string input = Console.ReadLine();
while (!input.ToLower().Equals("exit"))
{
Package p = new Package(PackageType.Data, postOffice.LocalClientEP, targetEP, input);
try
{
postOffice.Send(p);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Write("Talk Demo> ");
input = Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
postOffice.EndListen(PostOffice.ListenAs.Client);
}
Console.WriteLine("Press any key to continue");
Console.ReadKey(true);
}
static void postOffice_PackageReceived(object sender, PackageReceivedEventArgs e)
{
if (e.Package.PackageType == PackageType.Data)
{
Console.WriteLine("\r\nFrom [" + e.Package.SourceEP.Address.ToString() + "]> " + e.Package.Data[0].ToString());
Console.Write("Talk Demo> ");
}
}
}
}