.net 使用线程时出现套接字问题
有人能解释一下为什么下面的代码不起作用吗.net 使用线程时出现套接字问题,.net,sockets,multithreading,socketexception,.net,Sockets,Multithreading,Socketexception,有人能解释一下为什么下面的代码不起作用吗 using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; using System.Threading; namespace SocketThreadingTest { class Program { static void Main(string[] arg
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace SocketThreadingTest
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(delegate()
{
BeginConnect(new IPEndPoint("some address"));
});
t.Start();
Console.ReadKey();
}
public static void BeginConnect(IPEndPoint address)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(address, ConnectCallback, socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
sock.EndConnect(ar);
Console.WriteLine("Connected {0}", sock.LocalEndPoint);
sock.Send(Encoding.UTF8.GetBytes("Hello"));
Console.WriteLine("success");
sock.Close();
}
catch (Exception ex)
{
Console.WriteLine("send ex " + ex);
if (sock != null)
sock.Close();
}
}
}
}
输出为(注意插座的本地端点):
当然,当我不使用线程并直接调用BeginConnect时,它可以正常工作。更令人费解的是,添加一个线程。睡眠时间足够长(1秒)也可以正常工作。
有什么想法吗?
谢谢。您的IPEndPoint应该包含一个端口——我甚至不确定端点将如何编译,因为这是必需的。您可以将端口作为IPendeddress的第二个参数提供,或修改BeginConnect方法,如下所示:
socket.BeginConnect(address, [port], ConnectCallback, socket);
…其中,[port]表示服务器上的侦听端口。使用单独的线程和BeginConnect有什么意义? 如果创建单独的线程(最好使用线程池),为什么要使用异步连接(在这种情况下,将从线程池中获取单独的线程) 有几种选择: 使用线程池和套接字。连接
class Program {
static void Connect(object o)
{
IPEndPoint address = (IPEndPoint)o;
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(address);
Console.WriteLine("Connected {0}", socket.LocalEndPoint);
socket.Send(Encoding.UTF8.GetBytes("Hello"));
Console.WriteLine("success");
socket.Close();
}
static void Main(string[] args)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 5111);
ThreadPool.QueueUserWorkItem(Connect, endPoint);
Console.ReadKey();
}
}
使用BeginConnect(无单独螺纹)
class Program {
static void Main(string[] args)
{
BeginConnect(new IPEndPoint(IPAddress.Loopback, 5111));
Console.ReadKey();
}
public static void BeginConnect(IPEndPoint address)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(address, ConnectCallback, socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
sock.EndConnect(ar);
Console.WriteLine("Connected {0}", sock.LocalEndPoint);
sock.Send(Encoding.UTF8.GetBytes("Hello"));
Console.WriteLine("success");
sock.Close();
}
catch (Exception ex)
{
Console.WriteLine("send ex " + ex);
if (sock != null)
sock.Close();
}
}
}
使用带有单独螺纹的BeginConnect:
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(delegate()
{
BeginConnect(new IPEndPoint(IPAddress.Loopback, 5111));
});
t.Start();
Console.ReadKey();
}
public static void BeginConnect(IPEndPoint address)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(address, ConnectCallback, socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
sock.EndConnect(ar);
Console.WriteLine("Connected {0}", sock.LocalEndPoint);
sock.Send(Encoding.UTF8.GetBytes("Hello"));
Console.WriteLine("success");
sock.Close();
}
catch (Exception ex)
{
Console.WriteLine("send ex " + ex);
if (sock != null)
sock.Close();
}
}
}
是否可能因为您没有等待初始线程,操作系统正在取消I/O请求?如果启动异步I/O的原始线程死亡,Windows将取消I/O请求 在本例中,您从一个线程调用BeginConnect,并让该线程终止,因此I/O被取消。现在,如果在套接字上调用Send()时启动的线程实际上没有死亡,那么可能会出现I/O没有被取消的情况 如果您真的希望这样做,可以尝试以下变化:
static void Main(string[] args)
{
Thread t = new Thread(delegate()
{
IAsyncResult ar = BeginConnect(new IPEndPoint("some address"));
// wait for the async connect to finish.
ar.WaitOne();
});
t.Start();
Console.ReadKey();
}
public static IAsyncResult BeginConnect(IPEndPoint address)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
return socket.BeginConnect(address, ConnectCallback, socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return null;
}
您创建的调用BeginConnect的线程在调用BeginConnect后退出。如果不让该线程结束,您是否看到任何不同的行为(API文档注意到,如果调用sock.BeginConnect的线程结束,则会出现问题,但这应该只是以前连接的套接字上的问题)是的,存在差异。正如我所说的,即使在调用Program.BeginConnect后添加一个小睡眠也可以实现这一点。API文档声明:“如果此套接字以前已断开连接,则必须在操作完成之前不会退出的线程上调用BeginConnect。这是基础提供程序的限制。”但正如您所述,这是一个新套接字,以前未断开连接…别傻了,乔治。。。当然,代码不会按原样编译。你以为我会在这里粘贴一个真正的服务器地址吗?!我认为写“someaddress”是一个足够强烈的暗示,这是运行此代码之前需要填充的地方。我知道这些选项,但BeginConnect是从单独的线程调用的。这是应用程序的设计。我在问为什么在这种情况下我会出错。我的第二个例子效果很好。。。您可以将此代码改为使用Thread类。我将示例改为使用Thread类。而且效果很好。我认为问题根本不在Thread类中,而是时间问题。你的代码和我的完全一样,我们得到了不同的结果。问题是,在我的机器上,线程在操作完成之前就存在了。请参阅我与上面nos的讨论。OK。我在自己的机器上复制了这种行为(现在,我正在尝试连接到外部主机)。。。并试图理解为什么这个代码不起作用。你能改用连接方法吗?
static void Main(string[] args)
{
Thread t = new Thread(delegate()
{
IAsyncResult ar = BeginConnect(new IPEndPoint("some address"));
// wait for the async connect to finish.
ar.WaitOne();
});
t.Start();
Console.ReadKey();
}
public static IAsyncResult BeginConnect(IPEndPoint address)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
return socket.BeginConnect(address, ConnectCallback, socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return null;
}