![](/img/trans.png)
[英]Android TCP Client can not receive data from TCP Server with wifi
[英]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
BufferedReader
的readLine()
方法,該方法讀取下一個換行符
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.