c# socket接收线程
本文关键字:线程 socket | 更新日期: 2023-09-27 18:13:20
我有一个套接字连接,我正在通过这个套接字发送数据。我所连接的服务器回答我的每一个正确的数据发送。我已经让消息工作,所以我收到的每条消息都有一个答案。有时,服务器喜欢将消息保留几秒钟,或者以不同的顺序发送。我的解决方案是生成一个线程,并让它围绕一个接收函数旋转。然而,使用MSDN上的套接字示例我有适合。它们使用一个简单的do/while循环结构。当我这样做的时候,我得到的是混乱的回复和/或不完整的数据。这是一个家庭作业,所以我必须手写客户端,而不是仅仅使用一个更容易的解决方案。这段代码可能有问题吗?我盯着它看太久了,我想我错过了一些简单的东西:
private static void ReceiveThread(Socket sock, ReceiverClass rc)
{
// Create a socket and pass in parameter converted from object socket
int receivedBytes = 0;
do
{
// receive data from socket
receivedBytes = sock.Receive(rc.buffer);
byte[] formattedMsg = new byte[receivedBytes];
Array.Copy(rc.buffer, formattedMsg, receivedBytes);
rc.sb.Append("<LF><CR>" + System.Text.Encoding.ASCII.GetString(formattedMsg) + "'r'n");
}
while (receivedBytes > 0);
}
编辑,增加生成接收线程的函数。(这是太长了,但我计划让它漂亮,当我让愚蠢的东西工作):
public void SendData(Socket sock)
{
// Set socket timeout
sock.ReceiveTimeout = 4000;
// Prepare file for IO operations
string path = @"c:'Logs'Lab2.Scenario3.WurdingerO.txt";
StreamWriter logWrite = File.AppendText(path);
// Get local ip address:
IPAddress ip = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).First();
string portNum = ((IPEndPoint)sock.LocalEndPoint).Port.ToString();
// response time for scenario 2 and 3
int responseTime = 0;
// Set up Stopwatch to keep track of time
Stopwatch stpWatch = new Stopwatch();
stpWatch.Start();
// setup for logging class
ReceiverClass rc = new ReceiverClass();
// setup receiving thread
Thread receiveThread = new Thread(delegate()
{
ReceiveThread(sock, rc);
});
receiveThread.Start();
// Counter to call client operations
for (int i = 0; i < MESSAGE_COUNT; i++)
{
string msTime = Convert.ToString(stpWatch.ElapsedMilliseconds);
if (msTime.Length > 10)
{
string newMSTime = "";
for (int t = 9; t >= 0; t++)
{
newMSTime += msTime[t];
}
msTime = newMSTime;
}
Classes.RequestBuilder reqB = new Classes.RequestBuilder();
byte[] sendMsg;
switch (scenarioNo)
{
case 1:
sendMsg = reqB.MessageBuildScenarioOne(sock, msTime,
ip.ToString(), portNum, serverPort, serverIP, i);
break;
case 2:
// set up response time delay
switch (i)
{
case 1:
responseTime = 1000;
break;
case 3:
responseTime = 3000;
break;
default:
responseTime = 0;
break;
}
sendMsg = reqB.MessageBuildScenarioTwo(sock, msTime,
ip.ToString(), portNum, serverPort, serverIP, i, responseTime);
break;
case 3:
// set up response time delay
switch (i)
{
case 1:
responseTime = 1000;
break;
case 3:
responseTime = 3000;
break;
default:
responseTime = 0;
break;
}
sendMsg = reqB.MessageBuildScenarioThree(sock, msTime,
ip.ToString(), portNum, serverPort, serverIP, i, responseTime);
break;
default:
sendMsg = reqB.MessageBuildScenarioOne(sock, msTime,
ip.ToString(), portNum, serverPort, serverIP, i);
break;
}
try
{
sock.Send(sendMsg);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
// Socket shutdown
sock.Shutdown(SocketShutdown.Send);
receiveThread.Join();
sock.Shutdown(SocketShutdown.Receive);
string date = System.DateTime.Now.ToString("MMddyyyy");
string time = System.DateTime.Now.ToString("HHmmss");
logWrite.Write(rc.sb.ToString());
logWrite.Write(date + "|" + time + "|0|0|");
// Close log file
logWrite.Close();
System.Windows.Forms.MessageBox.Show("Finished");
}
编辑:我在发送操作后放置了一个睡眠计时器,这解决了我遇到的问题。谢谢你!
我想我也有类似的问题。
我使用Socket类发送JSON字符串,突然JSON。. NET将抛出异常。我检查了字符串,看到正在处理2个JSON(根)对象。然后我拼凑了一个最小的例子,发现套接字将隐藏*任何未读的数据(未读=没有。receive尚未被调用,并且。receive将清除隐藏)。
*stash:我不确定这是否是正确的术语。这对我来说很有意义。
这是我的测试。如果您想运行它,创建一个新的测试类并安装XUnit。
/// <summary>
/// Testing Net Sockets..
/// </summary>
/// <author>Jeff Hansen</author>
public class SocketTests
{
/// <summary>
/// The local endpoint for the server. There's no place like 127.0.0.1
/// </summary>
private IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1337);
/// <summary>
/// Tests that a call to .Receive will return all unread data.
/// </summary>
/// <author>Jeff Hansen</author>
[Fact]
public void ReceiveWillReadAllUnreadData()
{
// We expect to receive double data.
const string expected = "HELLOHELLO";
const string dataToSend = "HELLO";
// Start the server in a background task.
// We do this because the receive call is blocking.
var bgTask = Task.Factory.StartNew(() =>
{
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// Bind to the endpoint and start listening.
server.Bind(endpoint);
server.Listen(10); // 10 is max allowed connections in queue (I think)
// Client connected, receive data
var connectingClient = server.Accept();
// So low-level we even get to allocate room for the data buffer manually.
var buf = new byte[1024];
// Hangs until data flows.
var sz = connectingClient.Receive(buf); // This is the size of the data we just received.
var data = Encoding.ASCII.GetString(buf, 0, sz); // We use the size to only grab what we need from the buffer.
Console.WriteLine("Data received: {0}", data);
// This is going to pass because we sent the data twice,
// and the call to Receive would not be able to complete in time
// for it to clear before more data becomes available.
Assert.Equal(expected, data);
/*
* BAM! Theory proven. We seriously had issues
* because we didn't understand how it worked. This is why you usually end
* your transmission with a newline.
*/
Console.WriteLine("Server closing");
server.Close();
}
catch (Exception e)
{
// Make sure we close the server.
server.Close();
throw;
}
});
// Create a client socket and connect it to the server.
// The server thread should have started it up by now.
var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(endpoint);
// Get the bytes of our string
var buffer = Encoding.ASCII.GetBytes(dataToSend);
// Send it out twice. This happens faster than the server will process it,
// so the data is stacking up. You would THINK that .Receive would
// simply return the first data sent to it, and the next time .Receive is called
// return the next. But that's not how it works, apparently.
client.Send(buffer);
client.Send(buffer);
// Wait for the server to finish whatever it's doing.
try
{
// We give it 3000ms to complete.
bgTask.Wait();
}
catch (AggregateException ag)
{
// Throw any esceptions that were thrown in the background thread.
ag.Handle(ex => { throw ex; });
}
// Close the client socket.
client.Close();
}
}
我们通过用换行符分隔数据来解决这个问题。
有趣的事实:我正在摆弄TcpClient,发现如果我不向流中写入换行符,它就不会发送任何东西-它只是挂在那里。不过可能是局部问题。有人愿意详细说明一下吗?