在c#中创建线程安全套接字类
本文关键字:安全套 套接字 安全 线程 创建 | 更新日期: 2023-09-27 18:06:22
我对Sockets
和Thread Safe
插座的一些概念有一些疑问。我有两个类,一个服务器类和一个客户端类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
// Loosely inspired on http://msdn.microsoft.com/en-us/library/fx6588te.aspx
namespace AsynchronousSockets
{
class Server
{
class StateObject
{
public Socket connection = null;
// Note that I use a very small buffer size
// for this example. Normally you'd like a much
// larger buffer. But this small buffer size nicely
// demonstrates getting the entire message in multiple
// pieces.
public const int bufferSize = 100000;
public byte[] buffer = new byte[bufferSize];
public int expectedMessageLength = 0;
public int receivedMessageLength = 0;
public byte[] message = null;
}
static ManualResetEvent acceptDone = new ManualResetEvent(false);
const int listenPort = 2500;
static void Main(string[] args)
{
Console.Out.WriteLine("This is the server");
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, listenPort);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
acceptDone.Reset();
Console.Out.WriteLine("Listening on port {0}", listenPort);
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
acceptDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void AcceptCallback(IAsyncResult ar)
{
try
{
acceptDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.connection = handler;
handler.BeginReceive(state.buffer, 0, StateObject.bufferSize,
SocketFlags.None, new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void ReadCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.connection;
int read = handler.EndReceive(ar);
if (read > 0)
{
Console.Out.WriteLine("Read {0} bytes", read);
if (state.expectedMessageLength == 0)
{
// Extract how much data to expect from the first 4 bytes
// then configure buffer sizes and copy the already received
// part of the message.
state.expectedMessageLength = BitConverter.ToInt32(state.buffer, 0);
state.message = new byte[state.expectedMessageLength];
Array.ConstrainedCopy(state.buffer, 4, state.message, 0, Math.Min(StateObject.bufferSize - 4, state.expectedMessageLength - state.receivedMessageLength));
state.receivedMessageLength += read - 4;
}
else
{
Array.ConstrainedCopy(state.buffer, 0, state.message, state.receivedMessageLength, Math.Min(StateObject.bufferSize, state.expectedMessageLength - state.receivedMessageLength));
state.receivedMessageLength += read;
}
// Check if we received the entire message. If not
// continue listening, else close the connection
// and reconstruct the message.
if (state.receivedMessageLength < state.expectedMessageLength)
{
handler.BeginReceive(state.buffer, 0, StateObject.bufferSize,
SocketFlags.None, new AsyncCallback(ReadCallback), state);
}
else
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
Console.Out.WriteLine("Received message: 'n");
Console.Out.WriteLine(Encoding.UTF8.GetString(state.message));
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using Client;
using System.Management;
// Loosely inspired on http://msdn.microsoft.com/en-us/library/bew39x2a.aspx
namespace AsynchronousSockets
{
class Program
{
static readonly IPAddress serverIP = IPAddress.Loopback;
const int serverPort = 2500;
static ManualResetEvent connectDone = new ManualResetEvent(false);
static ManualResetEvent sendDone = new ManualResetEvent(false);
static void Main(string[] args)
{
Console.Out.WriteLine("This is the client");
Console.Out.WriteLine("Write the message to send. End with an emtpy line to start the transmisison. 'n");
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
for (int i = 0; i <= 10000; i++)
{
String message = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss") + " : Message sended by " + userName + ".";
Console.Out.WriteLine("Sending message: ...'n");
Console.Out.Write(message);
Console.Out.Write("'n");
Thread.Sleep(10);
Console.Out.WriteLine("Sleeping ...'n");
SendMessageAsync(message);
}
Console.Out.WriteLine("Sending finished by " + userName + "! 'n");
}
static void SendMessageAsync(string message)
{
// Initiate connecting to the server
Socket connection = Connect();
// block this thread until we have connected
// normally your program would just continue doing other work
// but we've got nothing to do :)
connectDone.WaitOne();
Console.Out.WriteLine("Connected to server");
// Start sending the data
SendData(connection, message);
sendDone.WaitOne();
Console.Out.WriteLine("Message successfully sent");
}
static Socket Connect()
{
try
{
IPEndPoint serverAddress = new IPEndPoint(serverIP, serverPort);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(serverAddress, new AsyncCallback(ConnectCallback), client);
return client;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
static void SendData(Socket connection, string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
// We store how much data the server should expect
// in the first 4 bytes of the data we're going to send
byte[] head = BitConverter.GetBytes(data.Length);
byte[] total = new byte[data.Length + head.Length];
head.CopyTo(total, 0);
data.CopyTo(total, head.Length);
connection.BeginSend(total, 0, total.Length, 0, new AsyncCallback(SendCallBack), connection);
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
connectDone.Set();
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
}
private static void SendCallBack(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
int bytes = client.EndSend(ar);
Console.Out.WriteLine("A total of {0} bytes were sent to the server", bytes);
sendDone.Set();
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
}
}
}
您可以看到,一旦client.exe
启动,如果server.exe
正在运行,它将接收Client
类发送的一些消息。
for (int i = 0; i <= 10000; i++)
{
String message = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss") + " : Message sended by " + userName + ".";
Console.Out.WriteLine("Sending message: ...'n");
Console.Out.Write(message);
Console.Out.Write("'n");
Thread.Sleep(10);
Console.Out.WriteLine("Sleeping ...'n");
SendMessageAsync(message);
}
,这个循环将执行10000次,循环之间的暂停时间为10毫秒。我从3个地方启动3个客户端(不同的windows用户同时登录),服务器日志为:
......
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user1.
Listening on port 2500
Listening on port 2500
Listening on port 2500
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user2.
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user3.
Listening on port 2500
Listening on port 2500
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user2.
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user3.
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
02-06-2014 11:24:30 : Message sended by MyComputer-PC'user1.
Listening on port 2500
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 8 bytes
Read 7 bytes
Received message:
......
在所有3个客户端停止后,我在' notepad++ '中打开日志文件,并计算以下结果:
count "MyComputer-PC'user1" => 8903
count "MyComputer-PC'user2" => 8464
count "MyComputer-PC'user3" => 8990
为什么?一些数据已经丢失,它应该呈现10.000 10.000 10.000…
我该如何解决这个问题?
另一件事,我想问si如何使套接字线程安全。
编辑
当套接字被拒绝时,我实际上得到了这个日志
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
Sending message: ...
03-06-2014 09:35:58 : Message sended by MyComputer-PC'User1.
Sleeping ...
connection.Connected False
connection.Blocking True
Connected to server
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Message successfully sent
谢谢。
问题似乎是在客户端使用ManualResetEvent
s。记住,必须手动重置ManualResetEvent
,否则在事件为Set()
之后的所有WaitOne()
调用将立即返回。因此,在发送第一条消息后,您的客户端在尝试发送数据之前不会等待套接字连接,正如我在机器上运行它时看到的记录的以下消息所示:
发送或接收数据的请求被拒绝,因为套接字未连接并且(当使用sendto调用在数据报套接字上发送时)没有提供地址
尝试在客户端将ManualResetEvent
s更改为AutoResetEvent
s(在WaitOne()
返回true后自动重置),这应该可以解决问题。