使用套接字连接将图像从 java 传输到 c# 时出现问题
problem with transfering image from java to c# using socket connection
我的 raspberry pi 上有一个 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("[=12=]", "");
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 循环的第一次迭代之后,我在此处 String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
.
收到 Overflow
错误
所以问题是——为什么即使我知道图像的大小(通常约为 290000 字节),客户端也只接收图像的一部分?或者有没有其他方法可以将图像从 java
传输到 c#
?或者 OpenCV
这行 Imgcodecs.imencode(".png", mat, matOfByte);
?
可能有问题
编辑 1: 我稍微调试了一下我的代码,发现了一件奇怪的事情。当我从 java
代码发送图像时,我打印字节数组大小,它给了我 388772
。所以当我从 c#
代码收到这个尺寸时,我得到了相同的数字。因此,我创建了一个具有此大小的 byte[]
,然后将字节设置为该数组。第一次迭代时一切都很好。但是在第二次迭代中,当 java 代码发送 "camera:cam1"
大小为 11
的字符串时,我的 c#
代码收到一个非常大的数字,如 11324982
,但它必须是 11
。所有这些让我想到 - 可能 java
发送的字节数比字节数组本身的大小多得多?或者 c#
收到的字节数比它需要的少很多?
我花了几个小时试图理解和解决这个问题。事实证明,java
服务器发送了所有正确的数据,但 c#
客户端无法一次接收到所有数据。我发现这个有用的问题:File transfer issue in c# and 。我的问题的解决方案原来是从服务器发送部分数据并在客户端接收部分数据。我更改了两个程序,它们看起来像:
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 == '[=11=]'));
String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
return rcv;
}
感谢您的帮助:)
我的 raspberry pi 上有一个 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("[=12=]", "");
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 循环的第一次迭代之后,我在此处 String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
.
收到 Overflow
错误
所以问题是——为什么即使我知道图像的大小(通常约为 290000 字节),客户端也只接收图像的一部分?或者有没有其他方法可以将图像从 java
传输到 c#
?或者 OpenCV
这行 Imgcodecs.imencode(".png", mat, matOfByte);
?
可能有问题
编辑 1: 我稍微调试了一下我的代码,发现了一件奇怪的事情。当我从 java
代码发送图像时,我打印字节数组大小,它给了我 388772
。所以当我从 c#
代码收到这个尺寸时,我得到了相同的数字。因此,我创建了一个具有此大小的 byte[]
,然后将字节设置为该数组。第一次迭代时一切都很好。但是在第二次迭代中,当 java 代码发送 "camera:cam1"
大小为 11
的字符串时,我的 c#
代码收到一个非常大的数字,如 11324982
,但它必须是 11
。所有这些让我想到 - 可能 java
发送的字节数比字节数组本身的大小多得多?或者 c#
收到的字节数比它需要的少很多?
我花了几个小时试图理解和解决这个问题。事实证明,java
服务器发送了所有正确的数据,但 c#
客户端无法一次接收到所有数据。我发现这个有用的问题:File transfer issue in c# and
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 == '[=11=]'));
String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);
return rcv;
}
感谢您的帮助:)