我从MSDN获取了TCPListener示例,并将其放在一个名为ListenForClients的方法中,然后使用该方法作为delgate启动一个Thread,就像这样。
public class MediaStreamSender
{
private List<TcpClient> clients = new List<TcpClient>();
private TcpListener tcpListener;
private Thread listenerThread;
private int port;
public MediaStreamSender(int port)
{
this.port = port;
listenerThread = new Thread(ListenForClients);
listenerThread.IsBackground = true;
listenerThread.Start();
}
private void ListenForClients()
{
try
{
// Set the TcpListener on port 13000.
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener tcpListener = new TcpListener(port);
tcpListener = new TcpListener(localAddr, port);
// Start listening for client requests.
tcpListener.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = tcpListener.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
if (tcpListener!= null)
{
tcpListener.Stop();
}
}
}
}
虽然这里的例子很奇怪,但我发现了一个我根本不懂的行为。
为什么我创建一个简单的命令行应用程序
class Program
{
static void Main(string[] args)
{
CreateASender();
Thread.Sleep(2000);
CreateASender();
Console.ReadLine();
}
private static void CreateASender()
{
MediaStreamSender sender = new MediaStreamSender(8660);
}
}
注意到我甚至给了2秒来清理套接字资源,因为我不知道是否有必要,它会抛出以下异常。
SocketException: System.Net.Sockets.SocketException (0x80004005): Only one usage of each socket address (protocol/network address/port) is normally permitted
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)
at System.Net.Sockets.TcpListener.Start()
at Construct.Media.MediaStream.MediaStreamSender.ListenForClients() in C:\-----------\MediaStreamSender.cs:line 113
我原本以为在我创建第二个MediaStreamSender时,第二个TcpListener,第一个对象的后台线程已经中止,finally块已经运行,关闭TcpListener,并释放我创建相同的第二个。
请注意,即使我将终结器放入MediaStreamSender对象中,仍然会发生这种情况
public class MediaStreamSender
{
private List<TcpClient> clients = new List<TcpClient>();
private TcpListener tcpListener;
private Thread listenerThread;
private int port;
.
.
.
~MediaStreamSender()
{
if (tcpListener != null)
{
tcpListener.Stop();
}
foreach (TcpClient client in clients)
{
client.Close();
}
listenerThread.Abort();
listenerThread.Join();
}
}
而且,即使是陌生人,如果我在Visual Studio中进行单元测试,只会创建一个MediaStreamSender,那么它每隔一段时间就会发生 。然后我一遍又一遍地进行单元测试。
无法承受的巨大文字墙,任何人都可以解释最新情况吗?