垃圾数据通过WiFi TCP连接从桌面传输到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  #include  #include  #include  #include  #include  #include  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连接上向客户端传输多个字符串。 我将客户端的输出重定向到一个文件,并在hex编辑器下打开它。 瞧,没有找到错误的数据。 我用连接到作为服务器的802.11b / g路由器的笔记本电脑进行了测试,并且硬连线桌面是客户端。 我已经消除了硬件问题,并在服务器端测试代码问题。 它必须在我实现Android客户端代码的方方面面。 我还尝试使用自动BufferedReader类来完成输入,以及使用InputStreamReader类手动处理输入。 两者都在第一个字符串后接收相同的垃圾输出。 这让我相信它在socket的输入流中的某个地方,但我该如何解决? 有人有什么建议吗?

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

 /* ** client.c -- a stream socket client demo */ #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #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()方法,该方法读取下一个换行符