簡體   English   中英

從桌面到Android的WiFi TCP連接傳輸的垃圾數據

[英]Garbage data transmitted in WiFi TCP connection from desktop to Android

我一直在四處尋找,並且無法找到解決這一特定問題的方法。 請原諒我,如果這是一個新手的錯誤,我剛剛離開學校,所以我正在閱讀盡可能多的書籍,以便了解移動設備編程。

目標:將基於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;
} 

謝謝您的幫助! Moscro

客戶:

您應該使用new String(buffer, 0, numread)創建字符串new String(buffer, 0, numread)因為並非所有緩沖區都已填充,因此read()不會覆蓋的現有字符將出現在字符串中。

您還應檢查numread == -1 ,因為這表示連接已關閉。

服務器:

sizeof(some_array)返回整個數組的大小(以字節為單位),這意味着您的服務器每次發送30個字節。 其中大多數將為null( \\0 ),這解釋了為什么C客戶端似乎工作,因為printf假定第一個空字節表示字符串的結尾。 但是,Java並不是為什么額外的字節在日志消息中顯示為垃圾的原因。

一種解決方案可能是:

  • 修改服務器以發送消息中的確切字符數,包括終止\\n ,這將是strlen(string) + 1
  • 然后在客戶端,拋棄第二個InputStreamReader並使用BufferedReaderreadLine()方法,該方法讀取下一個換行符

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM