如上所述,我正在尝试用 c 语言创建一个 tcp Linux 服务器来接受数据,执行一些处理然后将其发送回来。
我尝试在客户端使用的代码发送数据然后读回:
TcpClient tcpclnt = new TcpClient();
tcpclnt.Connect("192.168.0.14", 1235);
NetworkStream stm = tcpclnt.GetStream();
_signal.WaitOne();
Image<Bgr, Byte> frame = null;
while (_queue.TryDequeue(out frame))
{
if (frame != null)
{
resizedBMPFrame = frame.Resize(0.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR).ToBitmap();
using (MemoryStream ms = new MemoryStream())
{
resizedBMPFrame.Save(ms, ImageFormat.Bmp);
byte[] byteFrame = ms.ToArray();
l = byteFrame.Length;
byte[] buf = Encoding.UTF8.GetBytes(l.ToString());
stm.Write(buf, 0, buf.Length);
stm.Write(byteFrame, 0, byteFrame.Length);
}
}
else
{
Reading = false;
}
int i;
Bitmap receivedBMPFrame;
byte[] receivedFramesize = new byte[4];
int j = stm.Read(receivedFramesize, 0, receivedFramesize.Length);
int receivedFramesizeint = BitConverter.ToInt32(receivedFramesize, 0);
byte[] receivedFrame = new byte[receivedFramesizeint];
j = stm.Read(receivedFrame, 0, receivedFrame.Length);
using (MemoryStream ms = new MemoryStream(receivedFrame))
{
receivedBMPFrame = new Bitmap(ms);
if (receivedBMPFrame != null)
{
outputVideoPlayer.Image = receivedBMPFrame;
}
else
{
Reading = false;
}
}
}
}
stm.Close();
tcpclnt.Close();
所以想法是它等待显示线程使用并发队列发送它正在显示的当前帧,然后它获取它,并将其设为大小的四分之一,将其转换为字节数组,然后发送其长度和然后它本身通过 TCP 套接字。
理论上,服务器获取它,执行一些处理,然后将其发回,因此它读取它的长度,然后读取新帧本身。
服务器代码如下:
while (1)
{
int incomingframesize;
int n;
n = read(conn_desc, framesizebuff, 6);
if ( n > 0)
{
printf("Length of incoming frame is %s\n", framesizebuff);
}
else
{
printf("Failed receiving length\n");
return -1;
}
char framebuff[atoi(framesizebuff)];
n = read(conn_desc, framebuff, atoi(framesizebuff));
if ( n > 0)
{
printf("Received frame\n");
}
else
{
printf("Failed receiving frame\n");
return -1;
}
printf("Ready to write\n");
int k = sizeof(framebuff);
n = write(conn_desc, &k, sizeof(int));
if (n <0)
{
printf("ERROR writing to socket\n");
}
else
{
printf("Return frame size is %d\n", k);
}
n = write(conn_desc, &framebuff, sizeof(char)*k);
if (n <0)
{
printf("ERROR writing to socket\n");
}
frameno++;
printf("Frames sent: %d\n", frameno);
}
所以它读取长度,然后读取实际的帧,这似乎可以工作,目前只是将其直接发送回来而不进行任何处理。然而,它似乎只适用于一个循环,如果我逐行单步执行客户端代码,服务器代码会运行一次,但在客户端读取第二次时,从服务器接收帧,服务器然后运行两次读取立即循环,无需等待另一次写入。第二次失败,似乎没有读到任何输出:
Length of incoming frame is
Failed receiving frame
没有数字,这对我来说是有道理的,因为我还没有发送另一个包含下一帧长度的写入。我只是想知道我错过了什么/为什么会这样?与第一个循环一样,它会等待来自客户端的写入命令。我想知道这是否意味着写入流中还有剩余数据,因此当它返回到顶部时,它会立即再次读取它?尽管它不会打印任何形式的数字,这对我来说意味着什么都没有......
任何帮助将不胜感激。
编辑/更新: 将服务器上的读/写部分更改为一次执行一个字节,如下所示:
while (ntotal != incomingframesize)
{
n = read(conn_desc, &framebuff[ntotal], sizeof(char));
ntotal = ntotal + n;
while (i < k)
{
m = write(conn_desc, &framebuff[i], sizeof(char));
这似乎解决了我遇到的问题,现在正在传输正确的数据:)
最佳答案
当客户端写入帧大小时,它使用某个对象的长度,但当服务器读取时,它总是尝试读取 6 个字符。您需要使用固定长度的帧大小!
读取时,您不能假设您获得了所需的字节数。如果>0,则返回值是实际读取的字节数。如果您收到的字节数少于您要求的字节数,则需要继续阅读,直到收到您期望的字节数。
首先读取,直到获得 6 个字节(帧大小)。
接下来读取,直到获得帧大小指示的字节数。
确保在所有位置使用相同的帧大小字节数。
编辑:
我还注意到在服务器中调用 write
时存在一个错误:
n = write(conn_desc, &framebuff, sizeof(char)*k);
framebuff
是指向数据的指针,所以您可能的意思是:
n = write(conn_desc, &framebuff[0], k);
关于c# - tcp 服务器在第一次循环后失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28561468/