【问题标题】:Sending image from C# Server to Java client through TCP socket通过 TCP 套接字将图像从 C# 服务器发送到 Java 客户端
【发布时间】:2011-11-16 23:01:53
【问题描述】:

我的服务器中有一个图像,我想通过套接字发送到我的 Java 客户端。在 c# 中,我转换为字节数组,然后尝试通过套接字发送。但是,C# 中的字节数组是无符号的,所以我尝试发送有符号字节数组 sbyte[] 但它不能通过clientSocket.Send() 方法发送。在 java 客户端,我需要将接收到的字节数组转换为 Image 对象。这是我在Image image = reader.read(0, param) 获得的异常跟踪。请帮我解决这个问题。

Exception in thread "main" javax.imageio.IIOException: Bogus marker length
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImageHeader(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readNativeHeader(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.checkTablesOnly(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.gotoImage(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readHeader(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(Unknown Source)
at ServerByteStreamWithoutOIS.main(ServerByteStreamWithoutOIS.java:54)

这是我的 C# 服务器代码:

class Program
{
static void Main(String[] args)
{
Socket sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// 2. Fill IP
IPAddress IP = IPAddress.Parse("147.174.117.187");
IPEndPoint IPE = new IPEndPoint(IP, 20229);

// 3. binding
sListen.Bind(IPE);

// 4. Monitor
Console.WriteLine("Service is listening ...");
sListen.Listen(2);

// 5. loop to accept client connection requests
while (true)
{
Socket clientSocket;
try
{
clientSocket = sListen.Accept();
}
catch
{
throw;
}


// send the file
byte[] buffer = ReadImageFile("1.jpg");

clientSocket.Send(buffer, buffer.Length, SocketFlags.None);
clientSocket.Close();
Console.WriteLine("Send success!");
}
}


private static byte[] ReadImageFile(String img)
{
FileInfo fileInfo = new FileInfo(img);
byte[] buf = new byte[fileInfo.Length];
FileStream fs = new FileStream(img, FileMode.Open, FileAccess.Read);
fs.Read(buf, 0, buf.Length);
fs.Close();
//fileInfo.Delete ();
GC.ReRegisterForFinalize(fileInfo);
GC.ReRegisterForFinalize(fs);
return buf;
}
}
}

这是我的 Java 客户端:

public class ServerByteStreamWithoutOIS {
public static void main(String[] args) throws IOException, ClassNotFoundException{
int port = 20229;
Socket sock = null; 
InetAddress addr = null;
addr = InetAddress.getByName("147.174.117.187");    
sock = new Socket(addr, port);
System.out.println("created socket!");
int count = 0;
while(true){
String line = "";
String realLine = "";
BufferedReader bReader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
byte[] buffer = null;
while((line=bReader.readLine() )!=null){
realLine = realLine + line;
System.out.println(line.getBytes());
}

buffer = realLine.getBytes();

//buffer = (byte[])ois.readObject();

ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("jpg");

ImageReader reader = (ImageReader) readers.next();
Object source = bis; // File or InputStream, it seems file is OK

ImageInputStream iis = ImageIO.createImageInputStream(source);
//Returns an ImageInputStream that will take its input from the given Object

reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();

Image image = reader.read(0, param);
//got an image file

BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
//bufferedImage is the RenderedImage to be written
Graphics2D g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
File imageFile = new File("image.bmp");
ImageIO.write(bufferedImage, "bmp", imageFile); 

System.out.println(imageFile.getPath());

//Thread.sleep(100);
System.out.println("Done saving");
}
}

}

【问题讨论】:

    标签: c# java image object tcp


    【解决方案1】:

    我相信错误是因为您将 Java 服务器中接收到的字节转换为字符串表示形式。这可能会导致错误,因为 jpg 是二进制数据,当某些二进制数据无法转换为字符串中的字符时,会发生一些转换,从而导致使用 getBytes() 函数时出错。

    如果您改为使用read(byte[],int,int]) 函数从输入流中读取字节,我认为您应该没问题。

    http://download.oracle.com/javase/1.5.0/docs/api/java/io/InputStream.html#read(byte[], int, int)


    编辑,添加一个工作代码示例

    Java 有符号字节的“问题”不是问题。在二进制中它们是相同的位,因此当写入文件时,会写入相同的位,因为它们仍然是相同的顺序。

    我写了一个 C# 客户端和一个 Java 服务器的例子,我开始工作了。我相信你能找到它的用处。

    服务器 - Java

    import java.io.BufferedInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ImageServer {
        public static void main(String[] args) {
            try {
                ServerSocket server = new ServerSocket(8000);
                Socket accept = server.accept();
                InputStream inputStream = accept.getInputStream();
                BufferedInputStream stream = new BufferedInputStream(inputStream);
                int length = readInt(inputStream);
                byte[] buf = new byte[length];
                for (int read = 0; read < length; ) {
                    read += stream.read(buf, read, buf.length - read);
                }
                stream.close();
    
                FileOutputStream fos = new FileOutputStream("image.png");
                fos.write(buf, 0, buf.length);
                fos.flush();
                fos.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private static int readInt(InputStream inputStream) throws IOException {
            byte[] buf = new byte[4];
            for (int read = 0; read < 4; ) {
                read += inputStream.read(buf, 0, 4);
            }
            return toInt(buf);
        }
    
        public static int toInt(byte[] b) {
            return (b[0] << 24)
                    + ((b[1] & 0xFF) << 16)
                    + ((b[2] & 0xFF) << 8)
                    + (b[3] & 0xFF);
        }
    }
    

    客户端 - C#

    using System;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    
    namespace Test.SendImageClient {
        public class Program {
            public static void Main(string[] args) {
                if (args.Length == 0) {
                    Console.WriteLine("usage: client imagefile");
                    return;
                }
                FileStream stream = File.OpenRead(args[0]);
    
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect("localhost", 8000);
                int length = IPAddress.HostToNetworkOrder((int)stream.Length);
                socket.Send(BitConverter.GetBytes(length), SocketFlags.None);
    
                byte[] buffer = new byte[1024];
                int read;
                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) {
                    socket.Send(buffer, 0, read, SocketFlags.None);
                }
                socket.Close();
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复。我用这段代码尝试了你的方法:byte[] buffer = new byte[3000];inputStream.read(buffer, 0, 3000); 现在我得到了异常Not a jpeg file starts with 0x04 0x48 我认为这是因为 c# 发送无符号字节数组,而 java 将其视为有符号字节数组。你知道无论如何我可以通过套接字将 sbyte 数组发送到 java 吗?谢谢
    • @mojorisinify:您能否验证这是否可能是因为字节序?查看stackoverflow.com/questions/92287/… 以获取如何将 int 转换为网络顺序的示例。如果在 Visual Studio 中设置断点,则可以检查 C# 字节数组中的第一个字节,并验证 Java 服务器中收到的第一个字节。
    • 顺便说一句,不是创建一个固定的字节数组,而是从您的 C# 客户端发送字节数组长度并在您的 Java 服务器中读取那么多字节。使用 read 函数的返回值来知道已经读取了多少字节,并迭代直到你拥有所有字节。
    • 实际上是好消息,现在使用相同的 inputstream.read() 它现在从 C# 获取图像,但图像已损坏。某些像素不正确。但在大多数情况下,图像是可见的。尽管Not a jpeg file: starts with 0xd9 0xff 的错误是相同的。如果是字节序,图像不会保存在java客户端中吗?
    • @mojorisinify 当然你可以保存它,但正如你所说,它已损坏。如果您检查收到的字节与发送的字节相比,您可以尝试验证它是因为字节顺序(字节序),它们的值是否相同?
    【解决方案2】:

    似乎接收到的字节没有与 jpeg 规范对齐(无法正确反序列化)。你确定服务器上的文件存在并且 c# byte[] 被正确填充了吗?也许在通过套接字发送之前尝试在服务器上写入文件,以确保您实际上正在读取服务器上的有效 jpeg。

    【讨论】:

    • 是的,文件存在于服务器上,C#字节已填满。我已经测试过,它实际上在 C# 中工作。问题是在您将其发送到 Java 客户端之后。我认为这是因为我不知道如何通过套接字发送 sbyte。 Java 获取未签名的字节并认为它是一个带符号的字节数组。
    猜你喜欢
    • 2012-12-01
    • 2019-08-08
    • 2019-03-12
    • 1970-01-01
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2017-05-26
    相关资源
    最近更新 更多