我正在使用 cloudQueue.BeginAddMessage 和 EndAddMessage 发送许多消息。我将尚未返回的开始数量限制为 500。但我遇到了代码 10048 的异常(表示套接字耗尽)。
Microsoft.WindowsAzure.Storage.StorageException: Unable to connect to the remote server ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted
我在搜索后发现的解决方案都建议修改注册表,但是由于这是在 Azure 中的工作角色中计划的,所以我不能这样做。
我还有其他插入表服务的功能,它们运行速度一样快,但没有任何问题。似乎 EndAddMessage 函数几乎没有关闭连接或其他东西(我对套接字的了解有限)。
我的问题:这里有天蓝色的错误吗?除了人为地减慢消息的添加速度之外,我应该怎么做才能解决这个问题?
这是我用来发送消息的测试功能。在我的例子中,在添加了大约 16500 条消息并且回调正确且稳定地结束后,它变慢了,过了一会儿抛出了上述异常。
对于长代码,我很抱歉,但这应该是复制粘贴,以便您重现问题。
异常从AsyncCallback endAddCallback
.
static void Main()
{
Console.SetBufferSize(205, Int16.MaxValue - 1);
// Set the maximum number of concurrent connections (12*6 in my case)
ServicePointManager.DefaultConnectionLimit = 12 * Environment.ProcessorCount;
//setting UseNagleAlgorithm to true reduces network traffic by buffering small packets of data and transmitting them as a single packet, but setting to false can significantly reduce latencies for small packets.
ServicePointManager.UseNagleAlgorithm = false;
//if true, "Expect: 100-continue" header is sent to ensure a call can be made. This uses an entire roundtrip to the service point (azure), so setting to false sends the call directly.
ServicePointManager.Expect100Continue = false;
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(__CONN_STRING);
CloudQueueClient client = storageAccount.CreateCloudQueueClient();
CloudQueue queue = client.GetQueueReference(__QUEUE_NAME);
queue.CreateIfNotExists();
List<Guid> ids = new List<Guid>();
for (Int32 i = 0; i < 40000; i++)
ids.Add(Guid.NewGuid());
SendMessages(queue, ids.Select(id => new CloudQueueMessage(id.ToString())).ToList().AsReadOnly());
}
public static void SendMessages(CloudQueue queue, IReadOnlyCollection<CloudQueueMessage> messages)
{
List<CloudQueueMessage> toSend = messages.ToList();
Object exceptionSync = new Object();
Exception exception = null;
CountdownEvent cde = new CountdownEvent(toSend.Count);
AsyncCallback endAddCallback = asyncResult =>
{
Int32 endedItem = (Int32)asyncResult.AsyncState;
try
{
queue.EndAddMessage(asyncResult);
Console.WriteLine("SendMessages: Ended\t\t{0}\t/{1}", endedItem + 1, toSend.Count);
}
catch (Exception e)
{
Console.WriteLine("SendMessages: Error adding {0}/{1} to queue: \n{2}", endedItem + 1, toSend.Count, e);
lock (exceptionSync)
{
if (exception == null)
exception = e;
}
}
finally { cde.Signal(); }
};
for (Int32 i = 0; i < toSend.Count; i++)
{
lock (exceptionSync)
{
if (exception != null)
throw exception;
}
//if number of added but not ended is larger than the MAX, yield and check again.
while (true)
{
Int32 currentOngoing = (i- (cde.InitialCount - cde.CurrentCount));
if (currentOngoing > 500)
Thread.Sleep(5);
else
break;
}
Console.WriteLine("SendMessages: Beginning\t{0}\t/{1}", i + 1, toSend.Count);
queue.BeginAddMessage(toSend[i], endAddCallback, i);
}
cde.Wait();
if (exception != null)
throw exception;
Console.WriteLine("SendMessages: Done.");
}