我正在开展一个在圣诞节前工作正常的项目,但突然间没有任何改变。
该项目涉及一个C ++,它监听特定端口并侦听在REST API中发布请求以处理数据并存储在数据库中。
它由一个Android库组成,它收集信息,然后将其作为HTTP POST发送到C ++应用程序上的其余API。
C ++应用程序打印出在完成任何处理之前直接从套接字接收的HTTP响应。首先,Android应用程序必须向C ++应用程序发送初始化请求,C ++打印请求并显示发送的数据,并成功实施并向Android发回包括会话cookie的响应。然后,我重新使用Android中的HttpClient发布包含大量数据的下一个请求,但此请求不起作用。
当单步执行android库时,我可以看到post值已经成功设置并且正用于执行HTTP请求,但是,C ++应用程序只接收HTTP头,而不是任何post数据。
如果在第二个请求中,我只用几个帖子字段替换帖子数据,那么C ++会看到帖子数据,所以看起来Android中的DefaultHTTPClient并不发送帖子数据。数据非常大。
以下是我在Android中发布数据的方式
if (httpClient == null)
{
//AndroidHttpClient client = new AndroidHttpClient();
httpClient = new DefaultHttpClient();
}
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 3000);
HttpConnectionParams.setSoTimeout(httpParams, 3000);
HttpPost httpPost = new HttpPost(serverURL);
//httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setHeader("Authorisation-Token", authorisationToken);
httpPost.setHeader("Connection", "close");
//httpPost.setHeader("Cookie", "SESSIONID=zd8d5n3kucysl4idug1911m7ye");
httpPost.setEntity(new UrlEncodedFormEntity(postData, "UTF-8"));
String headers = "";
responseHandler = new ResponseHandler<String>()
{
@Override
public String handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException
{
return EntityUtils.toString(httpResponse.getEntity());
}
};
responseBody = httpClient.execute(httpPost, responseHandler);
Log.d("Response", responseBody);
//httpClient = null;
if (responseBody != null && !responseBody.isEmpty())
{
httpClient.getConnectionManager().closeIdleConnections(0, TimeUnit.NANOSECONDS);
JSONObject jsonObject = new JSONObject(responseBody);
return jsonObject;
}
else
{
httpClient.getConnectionManager().closeIdleConnections(0, TimeUnit.NANOSECONDS);
return null;
}
例如,帖子数据的创建方式如下:
postData = new ArrayList<>();
postData.add(new BasicNameValuePair("Test", "Item 1"));
postData.add(new BasicNameValuePair("Test 2", "Item 2"));
并将上述内容传递给ASyncTask的execute命令。
以下是我从C ++接收套接字数据的方法
string LinuxSocket::receiveDataOnSocket(int *socket)
{
string receiveData = "";
char * temp = NULL;
int bytesReceived = 0;
do
{
bytesReceived = recv(*socket, this->buffer, this->bufferLength, 0);
if (bytesReceived < 0)
{
stringstream logstream;
logstream << "Failed to read data on socket. Error: " << strerror(bytesReceived);
this->bitsLibrary->writeToLog(logstream.str(), "LinuxSocket", "receiveDataOnSocket");
this->closeSocket(socket);
throw SocketException(strerror(bytesReceived));
}
//If we got here then we should be able to get some data
temp = new char[bytesReceived + 1];
strncpy(temp, this->buffer, bytesReceived);
temp[bytesReceived] = '\0';
receiveData.append(temp);
delete[] temp;
temp = NULL;
memset(this->buffer, 0, this->bufferLength);
} while (bytesReceived == this->bufferLength);
return receiveData;
}
我发送的帖子数据如下:
POST /crash HTTP/1.1
User-Agent: My Android User Agent
Authorisation-Token: DlzSIkx4ro*OatHCV6epfWY0F
Connection: close
Content-Length: 1231
Content-Type: application/x-www-form-urlencoded
Host: 192.168.1.123:500
Cookie: SESSIONID=6rc5q1db0z8lupe5uij5ten3mw
Cookie2: $Version=1
Severity=Critical&DeviceID=36e85611db16c7fa&VersionName=1.5&DeviceType=Android&ROMBuild=sdk_gphone_x86-userdebug+8.0.0+OSR1.170901.056+4497355+dev-keys&KernelVersion=3.18.81%2B&DeviceBrand=google&DeviceModel=Android+SDK+built+for+x86&APILevel=26&ScreenResolution=1080+x+1776&Locale=English&MobileNetwork=Android&CrashType=Handled&ExceptionType=java.lang.Exception&Stacktrace=java.lang.Exception%3A+Standard+Exception+been+thrown%0A%09at+com.MyCompany.MyApp.MainActivity%242.onClick%28MainActivity.java%3A67%29%0A%09at+android.view.View.performClick%28View.java%3A6256%29%0A%09at+android.view.View%24PerformClick.run%28View.java%3A24701%29%0A%09at+android.os.Handler.handleCallback%28Handler.java%3A789%29%0A%09at+android.os.Handler.dispatchMessage%28Handler.java%3A98%29%0A%09at+android.os.Looper.loop%28Looper.java%3A164%29%0A%09at+android.app.ActivityThread.main%28ActivityThread.java%3A6541%29%0A%09at+java.lang.reflect.Method.invoke%28Native+Method%29%0A%09at+com.android.internal.os.Zygote%24MethodAndArgsCaller.run%28Zygote.java%3A240%29%0A%09at+com.android.internal.os.ZygoteInit.main%28ZygoteInit.java%3A767%29%0A&CustomProperty=%7B%22Test+Non+Json+Property%22%3A%22Here+is+my+value%22%7D&AppID=15869700
作为示例,成功运作的后期数据如下:
POST /initialise HTTP/1.1
Authorisation-Token: DlzSIkx4ro*OatHCV6epfWY0F
Connection: close
Content-Length: 48
Content-Type: application/x-www-form-urlencoded
Host: 192.168.1.123:500
User-Agent: My Android User Agent
ApplicationID=15869700&DeviceID=36e85611db16c7fa
我还从Android捕获了请求,并从Rest API测试客户端Insomnia.Rest发送了它,并将其发送到Rest API,C ++成功查看了所有帖子数据,因此它看起来像问题是如果Android库有一定的大小,它就不会发送帖子数据。
是这样吗,我怎么能绕过这个?
答案 0 :(得分:0)
我发现了这个问题,我已经做了两件事来解决这个问题。
没有发送任何帖子数据的问题,我从org.apache.DefaultHTTPClient更改为OkHTTPClient。通过查看Google,看起来apache版本已被弃用,OkHTTPClient无论如何都是首选的HTTP客户端。然后发送了一些发布数据但不是一切。这让我想到了第二个修复(我不认为问题实际上是apache客户端,我认为这是我的C ++在套接字上接收数据)。
我做的第二个修复是在C ++应用程序中更改我的receiveDataOnSocket函数。
当我从事套接字到套接字通信时,通常如果缓冲区已满,那么通常我可以期待接收更多数据,如果缓冲区只是部分满,那么所有数据都会被发送并返回收到的数据。
看起来HTTP没有必要发送接收套接字上的缓冲区可以处理的数量,因此我更改了套接字上的接收数据,以便在接收数据时处理数据以查找内容-Length标题,以及我可能拥有的身体长度,然后在每次后续的recv
调用中,我将当前的身体数量增加receiveBytes计数,如果身体长度等于内容长度我停止接收套接字上的数据并返回HTTP请求。