[英]problem with transfering image from java to c# using socket connection
我的树莓派上有一个java
程序(服务器),而我的电脑(客户端)上有一个c#
程序。 我想不断地将图像从树莓上的相机传输到我的c#
程序。 我在某处找到了如何通过套接字连接连接java
和c#
代码。 我的Java代码:
public static void Start()
{
new Thread(() -> {
while (true)
{
try
{
System.out.println("waiting for connection");
Socket socket = server.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
System.out.println("got connection");
SetOutput("Hello", os);
String fromClient = GetInput(is);
System.out.println(fromClient);
if(fromClient.equals("Hello"))
{
System.out.println("beginning");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
while(run)
{
SetOutput("camera:cam1", os);
SetOutput(Base64.getEncoder().encodeToString(MatValue()), os);
}
System.out.println("closed");
SetOutput("-1", os); // close client
fromClient = GetInput(is);
if (fromClient.equals("Closed"))
socket.close();
}
} catch (IOException|ArrayIndexOutOfBoundsException exception) {
exception.printStackTrace();
}
}
}).start();
}
public static byte[] MatValue()
{
Mat mat = new Mat();
camera.read(mat);
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".png", mat, matOfByte);
byte[] bytes1 = matOfByte.toArray();
return bytes1;
}
private static String GetInput(InputStream is) throws IOException
{
byte[] lenBytes = new byte[4];
is.read(lenBytes, 0, 4);
int len = (((lenBytes[3] & 0xff) << 24) | ((lenBytes[2] & 0xff) << 16) |
((lenBytes[1] & 0xff) << 8) | (lenBytes[0] & 0xff));
byte[] receivedBytes = new byte[len];
is.read(receivedBytes, 0, len);
String received = new String(receivedBytes, 0, len);
return received;
}
private static void SetOutput(String data, OutputStream os) throws IOException
{
byte[] toSendBytes = data.getBytes("ASCII");
int toSendLen = toSendBytes.length;
byte[] toSendLenBytes = new byte[4];
toSendLenBytes[0] = (byte)(toSendLen & 0xff);
toSendLenBytes[1] = (byte)((toSendLen >> 8) & 0xff);
toSendLenBytes[2] = (byte)((toSendLen >> 16) & 0xff);
toSendLenBytes[3] = (byte)((toSendLen >> 24) & 0xff);
os.write(toSendLenBytes);
os.write(toSendBytes, 0, toSendLen);
}
我应该说我正在使用OpenCV
从相机获取图像。 这是c#
代码:
internal class Client
{
public string outString = "";
private bool stopThread = false;
private IPEndPoint ipPoint;
private Socket sct;
private Thread thread;
internal Client(IPEndPoint ipPoint)
{
this.ipPoint = ipPoint;
sct = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void StartListening()
{
thread = new Thread(() => { Listening(); });
thread.IsBackground = true;
thread.Start();
}
private void Listening()
{
sct.Connect(ipPoint);
Thread.Sleep(1000);
outString = GetInput(sct);
SetOutput("Hello", sct);
try
{
while (!this.stopThread)
{
outString = GetInput(sct);
string[] subs = outString.Split(':');
switch (subs[0])
{
case "camera":
System.Diagnostics.Debug.WriteLine("camera");
string stringImg = ValidateBase64EncodedString(GetInput(sct));
byte[] data = Convert.FromBase64String(stringImg);
File.WriteAllBytes(Directory.GetCurrentDirectory() + @"\testt.png", data);
break;
}
}
sct.Shutdown(SocketShutdown.Both);
sct.Close();
}
catch (SocketException e)
{
StopListening();
}
}
private static string ValidateBase64EncodedString(string inputText)
{
string stringToValidate = inputText;
stringToValidate = stringToValidate.Replace('-', '+'); // 62nd char of encoding
stringToValidate = stringToValidate.Replace('_', '/'); // 63rd char of encoding
stringToValidate = stringToValidate.Replace("\\", "");
stringToValidate = stringToValidate.Replace("\0", "");
switch (stringToValidate.Length % 4) // Pad with trailing '='s
{
case 0: break; // No pad chars in this case
case 2: stringToValidate += "=="; break; // Two pad chars
case 3: stringToValidate += "="; break; // One pad char
default:
throw new System.Exception(
"Illegal base64url string!");
}
return stringToValidate;
}
private static void SetOutput(string data, Socket clientSocket)
{
int toSendLen = System.Text.Encoding.ASCII.GetByteCount(data);
byte[] toSendBytes = System.Text.Encoding.ASCII.GetBytes(data);
byte[] toSendLenBytes = System.BitConverter.GetBytes(toSendLen);
clientSocket.Send(toSendLenBytes);
clientSocket.Send(toSendBytes);
}
private static string GetInput(Socket clientSocket)
{
byte[] rcvLenBytes = new byte[4];
clientSocket.Receive(rcvLenBytes);
UInt32 rcvLen = BytesToInt(rcvLenBytes);
byte[] rcvBytes = new byte[rcvLen];
clientSocket.Receive(rcvBytes, (int)rcvLen, SocketFlags.None);
String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
return rcv;
}
private static UInt32 BytesToInt(byte[] arr)
{
UInt32 wd = ((UInt32)arr[3] << 24) | ((UInt32)arr[2] << 16) | ((UInt32)arr[1] << 8) | (UInt32)arr[0];
return wd;
}
public void StopListening()
{
this.stopThread = true;
thread.Abort();
try
{
sct.Shutdown(SocketShutdown.Both);
sct.Close();
}
catch (Exception e)
{
}
}
}
所以我在某处阅读 - 当我想传输图像时,我应该将其编码为Base64
,所以我在传输时将其编码为Base64
。 以及关于这个问题。 当我运行我的程序时,它们正常工作。 但是,当我从c#
客户端连接到java
服务器并开始连接时,我只能从客户端的相机获取图像的一部分: .
在客户端代码中 while 循环的第一次迭代之后,我在此处收到Overflow
错误String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
.
所以问题是 - 为什么即使我知道图像的大小(通常约为 290000 字节),客户端也只收到图像的一部分? 或者有没有其他方法可以将图像从java
传输到c#
? 或者在这一行中OpenCV
有问题Imgcodecs.imencode(".png", mat, matOfByte);
?
编辑 1:我调试了我的代码并看到了一件奇怪的事情。 当我从java
代码发送和图像时,我打印字节数组大小,它给了我388772
。 所以当我从c#
代码中收到这个大小时,我得到了相同的数字。 因此,我创建了一个具有此大小的byte[]
,然后将字节设置为该数组。 在第一次迭代中,一切都很好。 但是在第二次迭代中,当 java 代码发送大小为11
"camera:cam1"
字符串时,我的c#
代码收到一个非常大的数字,如11324982
,但它必须是11
。 所有这些都让我想到了 - 可能是java
发送的字节比字节数组本身的大小多得多? 或者可能是c#
接收的字节比它需要的少得多?
我花了几个小时试图理解和解决这个问题。 事实证明, java
服务器正在发送所有正确的数据,但c#
客户端无法一次接收所有数据。 我发现了这个有用的问题: c#和C# 中的文件传输问题- 套接字未接收所有字节。 我的问题的解决方案原来是从服务器发送部分数据并在客户端接收部分数据。 我改变了两个程序,它们看起来像:
private static void SetOutput(String data, OutputStream os) throws IOException
{
byte[] toSendBytes = data.getBytes("ASCII");
int toSendLen = toSendBytes.length;
// System.out.println(toSendLen);
byte[] toSendLenBytes = new byte[4];
toSendLenBytes[0] = (byte)(toSendLen & 0xff);
toSendLenBytes[1] = (byte)((toSendLen >> 8) & 0xff);
toSendLenBytes[2] = (byte)((toSendLen >> 16) & 0xff);
toSendLenBytes[3] = (byte)((toSendLen >> 24) & 0xff);
os.write(toSendLenBytes);
if (toSendLen > 10240)
{
for (int i = 0; i < toSendLen; i += 10240)
{
byte[] toSend;
if (i + 10240 > toSendLen)
{
toSend = Arrays.copyOfRange(toSendBytes, i, toSendLen);
os.write(toSend, 0, toSendLen - i);
}
else
{
toSend = Arrays.copyOfRange(toSendBytes, i, i + 10240);
os.write(toSend, 0, 10240);
}
}
}
else
{
os.write(toSendBytes, 0, toSendLen);
}
// os.write(toSendBytes, 0, toSendLen);
}
和c#
:
private static string GetInput(Socket clientSocket)
{
byte[] rcvLenBytes = new byte[4];
clientSocket.Receive(rcvLenBytes);
UInt32 rcvLen = BytesToInt(rcvLenBytes);
// System.Diagnostics.Debug.WriteLine(rcvLen);
byte[] rcvBytes;
if (rcvLen > 10240)
{
byte[] clientData;
List<byte> rcvBytesList = new List<byte>();
int totalBytes = 0;
while (totalBytes < rcvLen)
{
if (rcvLen - totalBytes < 10240)
{
clientData = new byte[rcvLen - totalBytes];
}
else
{
clientData = new byte[10240];
}
int bytesReceived = clientSocket.Receive(clientData);
rcvBytesList.AddRange(clientData);
totalBytes += bytesReceived;
}
rcvBytes = rcvBytesList.ToArray();
}
else
{
rcvBytes = new byte[rcvLen];
clientSocket.Receive(rcvBytes, (int)rcvLen, SocketFlags.None);
}
//System.Diagnostics.Debug.WriteLine(rcvBytes.Count(n => n == '\0'));
String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
return rcv;
}
感谢您尝试帮助我:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.