草庐IT

java - 桌面到安卓的WiFi TCP连接传输的垃圾数据

coder 2023-12-17 原文

我一直在四处寻找,但未能找到解决这个特定问题的方法。如果这是一个新手错误,请原谅我,我刚从学校毕业,所以我正在阅读尽可能多的书籍以了解移动设备编程。

目标: 将数据从基于 PC 的套接字服务器无线传输到基于 Android 的客户端 (802.11 b/g),然后客户端将处理所述数据以输出给用户。

问题: Android 手机的输入流缓冲区中接收到大量错误的垃圾数据。

程序: 我已经编写和/或修改了三段不同的代码。首先是在我的笔记本电脑上运行的服务器端程序。原始源代码可以在这里找到:beej.us/guide/bgnet/examples/server.c(感谢 Beej 的源代码!)。我修改了它以删除警告/错误,并添加了我自己的连续数据输入循环以用于测试目的。这是修改后的代码:

    /* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

void error(char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno;  //, clilen;

     //Modified this fromt he original author's code, as
     //the function is looking for clilen to be of type
     //socklen_t, not int
     socklen_t clilen;

     char buffer[256];
     struct sockaddr_in serv_addr, cli_addr;
     int n;

     if (argc < 2) 
     {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");

     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);

     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");

     //Added this for some clarity 
     printf("Starting to listen on the socket now..\n");
     listen(sockfd,5);


     clilen = sizeof(cli_addr);

     newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);

     //Let me know a socket connection has been established
     printf("Socket established!\n");


     if (newsockfd < 0) 
          error("ERROR on accept");

     bzero(buffer,256);

     //Don't want this socket to block and read, only to write 
     //Modified from the original author
     //n = read(newsockfd,buffer,255);

     //if (n < 0) error("ERROR reading from socket");
     //printf("Here is the message: %s\n",buffer);

     //n = write(newsockfd,"Hello, socket!",18);

     const int SIZE_OF_STRING = 30;
     char string[SIZE_OF_STRING];
     int i = 0;

     for (i = 0; i < SIZE_OF_STRING; ++i)
     {
         string[i] = '\0';
     }

     //Ask input from the user until the word "quit" is seen
     //then close the socket 
     while (!strstr(string, "quit"))
     {
        printf("Please enter something to send to the phone.\n");
        scanf("%s", string);
        strcat(string, "\n");
        n = write(newsockfd, string, sizeof(string));
        if (n < 0) error("ERROR writing to socket");
     }

     printf("\n\nexiting..\n");

     close(newsockfd);
     close(sockfd);

     return 0; 
}

Android 代码如下:

public class SmartSawLineDrawSocketThread extends Thread 
{

    private Handler smartSawMainThreadCommunicationHandle_;
    private Socket smartSawSocketHandle_;
    private InputStream smartSawSocketInputStreamHandle_;
    private BufferedReader smartSawSocketInputBuffer_;
    private InputStreamReader smartSawSocketInputStreamReader_;
    private boolean threadRunning_ = false;
    private boolean isConnected_;
    private char buffer[] = new char[50];



    //Grab the thread's communication handle for use with sending messages to the UI
    //Thread
    public SmartSawLineDrawSocketThread(Handler handle)
    {
        smartSawMainThreadCommunicationHandle_ = handle;
        threadRunning_ = true;
        isConnected_ = false;
    }

    //Attempt a connection to the host
    public int SmartSawLineDrawSocketThreadConnect(String hostIP, String hostPort)
    {
        int rval = 0;
        Log.i("info", "hostIP = " + hostIP);
        Log.i("info", "hostPort = " + Integer.parseInt(hostPort.trim()));
        try 
        {
            smartSawSocketHandle_ = new Socket(hostIP.trim(), Integer.parseInt(hostPort.trim()));
            if (rval == 0)
            {
                smartSawSocketInputBuffer_ = new BufferedReader(new InputStreamReader(smartSawSocketHandle_.getInputStream()));
                smartSawSocketInputStreamReader_ = new InputStreamReader(smartSawSocketHandle_.getInputStream());
                if (smartSawSocketInputBuffer_ != null)
                {
                    isConnected_ = true;
                }
                else
                {
                    Log.e("error", "Input buffer pointer was null!");
                }
            }
        } 
        catch (UnknownHostException e) 
        {
            rval = 1;
            Log.i("info", "unknown host message e when connecting:" + e);
            e.printStackTrace();
            isConnected_ = false;
        }
        catch (IOException e) 
        {
            rval = 2;
            Log.i("info", "unknown IOException e when connecting:" + e);
            e.printStackTrace();
            isConnected_ = false;
        }
        catch (SecurityException e)
        {
            rval = 3;
            Log.i("info", "Need to set a security setting somewhere");
        }


        Log.i("info", "Rval returned with " + rval);    

        return rval;
    }

    //Disconnect from the server
    public void SmartSawLineDrawSocketThreadDisconnect()
    {
        try 
        {
            smartSawSocketHandle_.close();
            isConnected_ = false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    //Once the thread has started running, make sure we're connected, and start
    //trying to listen for messages
    @Override 
    public void run()
    {
        Log.i("info", "Made it into the run() loop of the thread.");
        while (threadRunning_)
        {
            if (isConnected_ == true)
            {
                try
                {
                    if (smartSawSocketInputStreamReader_.ready() == true)
                    //(smartSawSocketInputBuffer_.ready() == true)
                    {
                        int numread = 0;
                        numread = smartSawSocketInputStreamReader_.read(buffer);

                        Log.i("info", "amount of characters read in: " + numread);

                        Message mainThreadMessage_ = Message.obtain();
                        Bundle mainThreadDataBundle_ = new Bundle();
                        mainThreadDataBundle_.putString("Zero", new String(buffer)); //smartSawSocketInputBuffer_.readLine());
                        mainThreadMessage_.setData(mainThreadDataBundle_);
                        mainThreadMessage_.setTarget(smartSawMainThreadCommunicationHandle_);
                        mainThreadMessage_.sendToTarget();
                        Log.i("info", "Received a string! Sent this to main thread: " + mainThreadDataBundle_.getString("Zero"));


                    }
                }
                catch (IOException e)
                {
                    Log.i("info","IO Exception in thread main loop, e was: " + e);
                }
            }


        }

    } 
}

家庭作业和测试: 我可以成功传输一个字符串,但之后的所有内容在 PC-Android 连接中都是无法理解的垃圾。想先做功课,我想消除服务器端代码。我采用了 Beej 的客户端代码 (beej.us/guide/bgnet/examples/client.c) 并将其修改为只是一个好的倾听者。我能够在基于 PC-PC 的 TCP 连接上向客户端传输多个字符串。我将客户端的输出重定向到一个文件,并在十六进制编辑器下打开它。瞧,没有发现错误的数据。我使用连接到 802.11b/g 路由器的笔记本电脑作为服务器,并使用有线台式机作为客户端进行了测试。我已经消除了服务器端的硬件问题和测试代码问题。它必须在我如何实现 Android 客户端代码的某个地方。我还尝试了自动 BufferedReader 类来执行我的输入,以及使用 InputStreamReader 类手动处理输入。两者都在第一个字符串之后收到相同的垃圾输出。这使我相信它位于套接字输入流中的某个位置,但我该如何解决呢?有人有什么建议吗?

以下是基于 PC 的客户端测试的代码:

/*
** client.c -- a stream socket client demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <arpa/inet.h>

#define PORT "27015" // the port client will be connecting to 

#define MAXDATASIZE 100 // max number of bytes we can get at once 

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[])
{
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];

    if (argc != 2) {
        fprintf(stderr,"usage: client hostname\n");
        exit(1);
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("client: socket");
            continue;
        }

        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("client: connect");
            continue;
        }

        break;
    }

    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return 2;
    }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
            s, sizeof s);
    printf("client: connecting to %s\n", s);

    freeaddrinfo(servinfo); // all done with this structure

    //Modified from the original to spit out all strings transmitted from the server, then close the socket
    //when finished.
    while (!strstr(buf, "close"))
    {
        numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0);
        if (numbytes)
        {
            printf("Received: \n");
            printf("%s", buf);
            printf("\n");
        }
    }

    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
        perror("recv");
        exit(1);
    }

    buf[numbytes] = '\0';

    printf("client: received '%s'\n",buf);

    close(sockfd);

    return 0;
} 

感谢您的帮助! 莫斯科

最佳答案

客户:

您应该使用 new String(buffer, 0, numread) 创建字符串,因为可能并非所有缓冲区都已填充,因此现有字符不会被 read() 将出现在字符串中。

您还应该检查 numread == -1,因为这表明连接已关闭。

服务器:

sizeof(some_array) 返回整个数组的大小(以字节为单位),这意味着您的服务器每次发送 30 个字节。其中大部分将为空 (\0),这解释了为什么 C 客户端似乎可以工作,因为 printf 假定第一个空字节表示字符串的结尾。然而,Java 不会,这可能就是日志消息中额外字节显示为垃圾的原因。

一个解决方案可能是:

  • 修改服务器以发送消息中的确切字符数,包括终止 \n,即 strlen(string) + 1
  • 然后在客户端中,放弃第二个 InputStreamReader,只使用 BufferedReaderreadLine() 方法,该方法读取下一个换行符

关于java - 桌面到安卓的WiFi TCP连接传输的垃圾数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4417816/

有关java - 桌面到安卓的WiFi TCP连接传输的垃圾数据的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  3. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  4. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  5. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  6. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  10. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

随机推荐