Android - 客户端关闭连接发送图像,然后接收回字符串

Posted

技术标签:

【中文标题】Android - 客户端关闭连接发送图像,然后接收回字符串【英文标题】:Android - Client closes connection an image is sent, before receiving a string back 【发布时间】:2022-01-08 15:36:19 【问题描述】:

我有一个 android 应用程序,它打开与服务器的套接字连接并将图像发送到 python 服务器。服务器接收到该图像并应该发回一个字符串以确认图像已被接收。但是,在我结束输出流后套接字关闭,因此服务器接收到图像但客户端无法从服务器接收字符串,因为客户端关闭了连接。 因此,我要做的是在套接字关闭之前返回一个字符串/文本,确认图像已到达用户客户端。

这是我的 Python 服务器,它以字节解码的形式接收图像并将其保存到目录中,然后发回一条消息:

from socket import *
import datetime
import cv2
import PIL.Image as Image
from PIL import ImageFile, Image
import io
import base64
import numpy as np
import pickle
import uuid


date_string = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M")

port = 9999
s = socket(AF_INET, SOCK_STREAM)
s.bind(('', port))
s.listen(1)

while True:
    conn, addr = s.accept()
    img_dir = '/home/Desktop/frames_saved/'
    img_format = '.png'
    try:
        print("Connected by the ",addr)
        #date_string = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M")
        filename = str(uuid.uuid4())
        with open(img_dir+filename+img_format, 'wb') as file:
            while True:
                data = conn.recv(1024*8)
                if data:
                    print(data)
                    try:
                        file.write(data)
                    except:
                        s = socket(AF_INET, SOCK_STREAM)
                        s.bind(('', port))
                        s.listen(1)
                        conn.sendall(("Hello World"))
                        

                    
                else:
                    print("no data")
    
                    break
    finally:
        conn.close() 

我要做的是在我的 android 客户端中接收编码字符串并打印/显示 toast。

Android 客户端代码:

 public class SendImageClient extends AsyncTask<byte[], Void, Void> 


        @Override
        protected Void doInBackground(byte[]... voids) 
            isSocketOpen = true;
            try 
                Socket socket = new Socket("192.168.0.14",9999);
                OutputStream out=socket.getOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(out);
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;

                while (isSocketOpen)
                    Log.d("IMAGETRACK", "Wrote to the socket[1]");
                    dataOutputStream.write(voids[0],0,voids[0].length);
                    while ((line = input.readLine()) != null)
                        Log.d("IMAGETRACK3", "Wrote to the socket[3]");
                    response.append(line);
                    Message clientmessage = Message.obtain();
                    clientmessage.obj = response.toString();
                    Log.d("[MESSAGE]", String.valueOf(clientmessage));
                    // Tries to receive a message from the server
                    out.close();
                    input.close();
                    if(isSocketOpen == false)
                        Log.d("CLOSED", "CLOSED CONNECTION");
                        socket.close();

                        break;
                    
                
                socket.close();
             catch (IOException e) 
                e.printStackTrace();
            


            return null;
        
    

此外,我注意到执行out.close(); 也会关闭流套接字。这是服务器发送和接收图像后的日志:

D/IMAGETRACK: Wrote to the socket[1]
D/IMAGETRACK: Wrote to the socket[1]
W/System.err: java.net.SocketException: Socket closed
W/System.err:     at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:124)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:161)
        at java.io.DataOutputStream.write(DataOutputStream.java:107)
        at MyApp.MainActivity$SendImageClient.doInBackground(MainActivity.java:2792)
        at MyApp.MainActivity$SendImageClient.doInBackground(MainActivity.java:2780)
        at android.os.AsyncTask$3.call(AsyncTask.java:394)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

如果我尝试在 while 循环之后移动 out.close();,客户端将向服务器发送无限量的数据,当我关闭服务器以结束接收的无限数据时,我将拥有一个 10MB 或更多的图像,具体取决于我收到字节的日志。

从外观上看,我认为我需要以某种方式停止发送图像而不关闭服务器以收听发送回的图像。在不关闭套接字的情况下如何做到这一点?

【问题讨论】:

如果客户端想要接收返回字符串,则不应关闭套接字。它看起来像 srrver 仅在客户端关闭套接字时将接收到的字节保存到文件中。你有很多东西要改变。重新连接未完成。 客户端不再关闭套接字,直到应用程序关闭,我也添加了从服务器返回的字符串 the string is apparently sent, but is not received by the android client 哪个字符串? 图像接收正确吗? 是的,我可以将它们连续发送到服务器并可视化它们在服务器中的保存位置。此外,logcat 打印到 D/IMAGETRACK: Wrote to the socket[1]。我刚刚尝试在应该接收字符串的代码下移动 out.close() 并且得到了相同的结果 【参考方案1】:

socket 关闭的原因很简单。我以前有这样的示例程序。你有 2 种选择。您发送和接收文件的架构不完整且不正确。

一种选择是您可以自己定义发送和接收的协议,这不是标准的。比如你可以定义##endoffile##等特殊字符,在你的图片之后发送,然后不要关闭socket。服务器了解图像已收到,仅此而已。然后在客户端调用receive方法直到socket结束,但在此之前,你必须发回数据字符串以确认图像已经收到,并且客户端在收到这个字符串时关闭socket。请记住明智地添加套接字超时以防止无限套接字等待。

第二种解决方案是可以使用HTTPFTP等标准协议,但必须读取这些协议的标准,例如标头和正文值,还要以multipart发送和接收文件。

【讨论】:

以上是关于Android - 客户端关闭连接发送图像,然后接收回字符串的主要内容,如果未能解决你的问题,请参考以下文章

从android客户端通过套接字发送后收到黑色图像

在将图像发送到服务器之前上传并裁剪图像[关闭]

计算机网络-TCP连接

TCP协议中RST异常关闭的问题

如何通过发送图像远程安装 android 应用程序? [关闭]

自己写了一个Android的APP,想用socket连接服务器