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 == nullreturn;
            
if (stream == nullreturn;

            BinaryFormatter binFormatter 
= new BinaryFormatter();
            binFormatter.Serialize(stream, package);
        }


        
public static Package Deserialize(Stream stream)
        
{
            
if (stream == nullreturn 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,
    }

}

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);
}


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;
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> ");
            }

        }

    }

}