I'm trying to write an RCON Client in dart, but I'm getting stuck at this point:
The server recives the packet but seems like it cannot read it properly as reply I'm getting:
Rcon auth failed from rcon whitelist address 2.xxx.xxx.169:52672
Even tough the password is right:
"rcon_password" = "foo" ( def. "" ) - remote console password.
I've provided links to the valve's wiki within the code comments.
This is my code at the moment:
Socket socket;
int _id = 1;
const int SERVERDATA_AUTH = 3;
const int SERVERDATA_AUTH_RESPONSE = 2;
const int SERVERDATA_EXECCOMMAND = 2;
const int SERVERDATA_RESPONSE_VALUE = 0;
void main() async {
socket = await Socket.connect('hexah.net', 27015);
await socket.listen(onSocketData, onError: onError, onDone: onDone);
await _write(SERVERDATA_AUTH, 'foo');
}
void _write(int type, String body) async {
var bodyASCII = ascii.encode(body); //Get ASCII string with Null terminator
// Should I use this or the other way? ??
var size = bodyASCII.length + 14;
var buffer = new Int8List(size).buffer;
var bdata = new ByteData.view(buffer);
bdata.setInt32(0, size - 4, Endian.little); //Byte requests length (32bit le signed int).
bdata.setInt32(4, _id, Endian.little); //Any integer (32bit le signed int).
bdata.setInt32(8, type, Endian.little); //Valid values: SERVERDATA_* (32bit le signed int).
int writepos = 12;
await bodyASCII.forEach((element) {
bdata.setInt8(writepos, element);
writepos +=1;
});
bdata.setInt16(size-2, 0, Endian.little); //Write the null terminators
await socket.write(bdata);
_id++;
}
void onSocketData(var data){
print(data);
}
void onError(var data, StackTrace stack){
print(stack);
}
void onDone(){
print('Connection terminated');
}
Here is also a small example with nodejs:
var size = Buffer.byteLength(body) + 14,
buffer = new Buffer(size);
buffer.writeInt32LE(size - 4, 0);
buffer.writeInt32LE(id, 4);
buffer.writeInt32LE(type, 8);
buffer.write(body, 12, size - 2, "ascii");
buffer.writeInt16LE(0, size - 2);
Do you have any ideas?
especially about getting properly the lengths.
This is how the packet payload should be
Using a RawSocket I get this as reply:
RawSocketEvent.write
RawSocketEvent.readClosed
EDIT:
I'm seeing that the same packet sent from nodejs resulted in a successful authentication but Dart failes, any ideas why this is happening? (converting the packets from nodejs & dart to an array they resulted the same)
Solved!
The issue was that I had to use a RawSocket and write something like this:
var packet = bdata.buffer.asInt8List();
await socket.write(packet, 0, packet.length);
Related
I made two extensions, one for firefox and one for chrome(will post only firefox code here, if it is necessary to post Chrome code, let me know, but it is extremely similar) that has some actions, calls to native host app. One of this calls returns a message with > 1 mb. According to https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging, "The maximum size of a single message from the application is 1 MB". According to chrome native messaging: how to receive > 1MB, data > 1mb must be chunked into less than 1 mb data and sent as many chunks. I Made a Java host app, and made a solution to chunk data. The data is chunked and many responses are sent, each with a chunk in a json string. The sending and responses worked ok, the messages are joined in an input of the web page, and the action works. However, after making this action, any other call fail. If I go to windows task manager, and kill the native host process, everything works again. If I do the action that gets chunked response, it works again, but next calls fail silently, firefox browser console gives me nothing. I guess there is something wrong with my solution. The actions work. When I do the action that receives more than 1 mb, the action works, but after that no other action work again. Any help is appreciated. Tell me if the question is not clear, or is a big mess, I will improve it. I did everythink I could to make it work, and it works, but oddly only one time, then it fails and do nothing. Sorry, but I can't say what the actions are, i mean, what im tryng to do, if it is realy necessary to know, I will ask my manager to explain it here.
Background.js
function sendNativeMessage(message) {
port.postMessage(message);
}
function onDisconnected() {
msg = '{"message": "Failed to connect: '+browser.runtime.lastError+'"}';
browser.tabs.query({active: true, currentWindow: true}, function(tabs){
browser.tabs.sendMessage(tabs[0].id, msg, function(response) {});
});
port = null;
}
function connect() {
var hostName = "com.companyname.hostname";
port = browser.runtime.connectNative(hostName);
port.onMessage.addListener(function(msg) {
browser.tabs.query({active: true, currentWindow: true}, function(tabs){
browser.tabs.sendMessage(tabs[0].id, JSON.stringify(msg), function(response) {});
});
});
port.onDisconnect.addListener(onDisconnected);
}
browser.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (port == null) {
connect();
}
sendNativeMessage(request);
});
Inject.js
//Prevent code being injected twice(probably because of click listeners on web page)
if (document.readyState !== "complete") {
browser.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
var obj = JSON.parse(msg);
if (!obj.success) {
(...)
}
if (obj.action == "doSomething") {
if (obj.last == "true") {
do something
}else {
var value = $("#input").val().trim() + obj.value.trim();
$("#input").val(value.trim());
}
}
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = browser.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
}
script.js
class extensionName{
getValues() {
window.postMessage({ type: "FROM_PAGE", text: {action: "getValues"} }, "*");
}
//This is the function that returns more than 1 mb.
dosomething(parameter1,parameter2,parameter3,parameter4) {
window.postMessage({ type: "FROM_PAGE", text: {action: "dosomething",parameter1Key:parameter1,parameter2Key:parameter2,parameter3Key:parameter3,parameter4Key:parameter4} }, "*");
}
}
Native app in Java (aux is an instance of an auxiliary class that has a sendMessage function that sends messages according to the native messaging protocol)
switch (parameter1) {
case "getValues":
json = functions.getValues();
aux.sendMessage(json);
break;
case "doSomething":
funcoes.doSomething(...);
break;
(...)
public String doSomething(...) {
(...)
Matcher m = Pattern.compile(".{1,565048}").matcher(valueMoreThan1Mb);
String chunk = "";
while(m.find()) {
System.setOut(originalStream);//let stream output values
chunk = newSignatureBase64.substring(m.start(), m.end());
//a json is done here, with needed parameters, action, chunked value.
json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"false\",\"value\":\""+chunk+"\"}";/Sorry for this. This code will be improved when everything is working.
aux.sendMessage(json);//auxiliar class sends message according to native messaging protocol.
System.setOut(dummyStream);//avoid 3rd party library output contents and mess native messaging port.
}
System.setOut(originalStream);//let stream output values
json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"true\"}";//Sorry for this. This code will be improved when everything is working.
aux.sendMessage(json);
System.setOut(dummyStream);
return "";
}
Auxiliar.java
public class Auxiliar {
public int getInt(byte[] bytes) {
return (bytes[3] << 24) & 0xff000000 | (bytes[2] << 16) & 0x00ff0000
| (bytes[1] << 8) & 0x0000ff00 | (bytes[0] << 0) & 0x000000ff;
}
public String readMessage(InputStream in) throws IOException {
byte[] b = new byte[4];
in.read(b);
int size = getInt(b);
//log(String.format("The size is %d", size));
if (size == 0) {
throw new InterruptedIOException("Blocked communication");
}
b = new byte[size];
in.read(b);
return new String(b, "UTF-8");
}
public boolean sendMessage(String message) {
try {
System.out.write(getBytes(message.length()));
System.out.write(message.getBytes("UTF-8"));
System.out.flush();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
//Use this in case the other method get deprecated
public byte[] getBytes(int length) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (length & 0xFF);
bytes[1] = (byte) ((length >> 8) & 0xFF);
bytes[2] = (byte) ((length >> 16) & 0xFF);
bytes[3] = (byte) ((length >> 24) & 0xFF);
return bytes;
}
}
I want to use a C-Function from Node.js by using N-API with node-addon-api module wrapper. This is the first time with N-API for me and I'm also a beginner with Node and C++. I have a experience in C programming of embedded systems but this Node.jS / N-API thing I don't understand completely yet...
What I wan't to do is to call a C-Function with this prototype from Node.js:
unsigned char *MyFunction(unsigned char *data, size_t size, size_t min, size_t max)
*data is a pointer to an array containing RGB image data [R0, G0, B0, R1, G1, B1, ...] with size size which should be processed in MyFunction (extracting RGB channels, inverting, ...).
What I have so far is this c++ code:
#include <napi.h>
using namespace Napi;
Napi::Value Method(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 3) {
Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
else {
const Napi::Array inputArray = info[0].As<Napi::Array>();
const float smin = info[1].As<Napi::Number>().FloatValue();
const float smax = info[2].As<Napi::Number>().FloatValue();
const unsigned int length = inputArray.Length();
unsigned int i;
Napi::Array outputArray = Napi::Array::New(env, length);
Napi::Array redArray = Napi::Array::New(env, length / 3);
Napi::Array greenArray = Napi::Array::New(env, length / 3);
Napi::Array blueArray = Napi::Array::New(env, length / 3);
// Extract Channels
for (i = 0; i < (length / 3); i++) {
redArray[i] = inputArray[i * 3];
greenArray[i] = inputArray[i * 3 + 1];
blueArray[i] = inputArray[i * 3 + 2];
}
// Apply Simple Color Balance to each channel
for (i = 0; i < (length / 3); i++) {
outputArray[i] = redArray[i];
}
return redArray; // Test => this works
}
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "Test"),
Napi::Function::New(env, Method));
return exports;
}
NODE_API_MODULE(module, Init)
and this is the node part:
const sharp = require('sharp');
sharp('testPic.jpg')
.resize(800, 600)
.toFile('SharpOut.jpg')
.then( data => {
console.log('Resize & Negate => OK')
// Extract Channel data
sharp('SharpOut.jpg')
.raw()
.toBuffer()
.then(data => {
var smin = 0.0;
var smax = 0.0;
var testArr = [];
for (let n = 0; n < data.length; n++) {
testArr[n] = data[n];
}
const HelloWorld = require('./build/Release/module.node');
const result = HelloWorld.Test(testArr, smin, smax);
})
.catch(err => {
console.log('ERROR during extraction of RED channel. ERR:');
console.log(err);
});
})
.catch( err => {
console.log('ERROR');
console.log(err);
});
My problems
Sharp outputs a buffer and not an array but with ArrayBuffer instead of Array I was not able to get working code. Compiling is ok but when I execute it in node I'm getting
Error: Invalid argument at D:\temp\testSCB\index.js:30:34
which is this line of code const result = HelloWorld.Test(testArr, smin, smax);)
If I change redArray[i] = inputArray[i * 3]; to redArray[i] = ~(inputArray[i * 3]); to invert the color I'm getting two errors:
error C2675: unary '~': 'Napi::Value' does not define this operator or a
conversion to a type acceptable to the predefined operator
and
error C2088: '~': illegal for class
My Question
What is the correct way to implement my c-Function to work from node.js?
Thanks for any help!
The node.js team has created Array buffer example by using the node-addon-api (the C++ wrapper to N-API), it can be accessed from the following URL. https://github.com/nodejs/node-addon-examples/tree/master/array_buffer_to_native/node-addon-api
If you are looking for a pure N-API implementation (without using any wrapper) then you may take a look on the following examples, this has been created while I was learning the pure N-API.
https://github.com/msatyan/MyNodeC/blob/master/src/mync1/ArrayBuff.cpp.
This example covers the following scenario:
Receive an ArrayBuffer from JavaScript
Create an ArrayBuffer at native layer and return it to JavaScript
Create a TypedArray at native layer and return it to JavaScript
Create an ArrayBuffer at native layer with externally allocated memory
and return it to JavaScript
Sample JavaScript usage of it is available: https://github.com/msatyan/MyNodeC/blob/master/test/TestArrayBuff.js
If you are starting a new native add-on module, I may encourage to use CMake.js instead of node-gyp (look like node-gyp is ending its support). You can get more information about the modern project structure from a sample project that I have created during my N-API study. https://github.com/msatyan/MyNodeC
I am running the Portable Device API to automatically get Photos from a connected Smart Phone. I have it all transferring correctly. The code that i use is that Standard DownloadFile() routine:
public PortableDownloadInfo DownloadFile(PortableDeviceFile file, string saveToPath)
{
IPortableDeviceContent content;
_device.Content(out content);
IPortableDeviceResources resources;
content.Transfer(out resources);
PortableDeviceApiLib.IStream wpdStream;
uint optimalTransferSize = 0;
var property = new _tagpropertykey
{
fmtid = new Guid(0xE81E79BE, 0x34F0, 0x41BF, 0xB5, 0x3F, 0xF1, 0xA0, 0x6A, 0xE8, 0x78, 0x42),
pid = 0
};
resources.GetStream(file.Id, ref property, 0, ref optimalTransferSize, out wpdStream);
System.Runtime.InteropServices.ComTypes.IStream sourceStream =
// ReSharper disable once SuspiciousTypeConversion.Global
(System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
var filename = Path.GetFileName(file.Name);
if (string.IsNullOrEmpty(filename))
return null;
FileStream targetStream = new FileStream(Path.Combine(saveToPath, filename),
FileMode.Create, FileAccess.Write);
try
{
unsafe
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, 1024);
} while (bytesRead > 0);
targetStream.Close();
}
}
finally
{
Marshal.ReleaseComObject(sourceStream);
Marshal.ReleaseComObject(wpdStream);
}
return pdi;
}
}
There are two problems with this standard code:
1) - when the images are saves to the windows machine, there is no EXIF information. this information is what i need. how do i preserve it?
2) the saved files are very bloated. for example, the source jpeg is 1,045,807 bytes, whilst the downloaded file is 3,942,840 bytes!. it is similar to all of the other files. I would of thought that the some inside the unsafe{} section would output it byte for byte? Is there a better way to transfer the data? (a safe way?)
Sorry about this. it works fine.. it is something else that is causing these issues
I've been trying to send JSON data from arduino mega by using ESP8266 as a wifi shield, and I've used node.js as a socket server. The problem is it seems that a server didn't receive any data. here is my code
#include <ArduinoJson.h>
#include "SoftwareSerial.h"
String ssid ="ssid";
String password="pwd";
//SoftwareSerial esp(22,23);// RX, TX
String data;
String server = "server ip";
byte objlength;
String url = "";
String temp,hum,weight;
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
//String uri = "yourURI";
void reset() {
Serial2.println("AT+RST");
delay(1000);
if(Serial2.find("OK") ) Serial.println("Module Reset");
}
void connectWifi() {
String cmd = "AT+CWJAP=\"" +ssid+"\",\"" + password + "\"";
Serial2.println(cmd);
delay(4000);
if(Serial2.find("OK")) {
Serial.println("Connected!");
Serial2.println("AT+CIPSTATUS");
delay(300);
while(Serial2.available()){Serial.print(Serial2.read());}
}
else {
connectWifi();
Serial.println("Cannot connect to wifi"); }
}
void setup() {
delay(5000);
// put your setup code here, to run once:
Serial2.begin(115200);
Serial.begin(115200);
reset();
connectWifi();
}
void loop() {
temp = 25.60;
hum = 65.3;
weight = 65.3;
root["weight"] = weight;
root["light"] = temp;
root["humid"] = hum;
objlength = root.measureLength();
senddata();
delay(10000);
}
void senddata()
{
int objlength = root.measureLength();
Serial2.println("AT+CIPSTART=\"TCP\",\"" + server + "\",1336");//start a TCP connection.
delay(500);
if( Serial2.find("OK")) {
Serial.println("TCP connection ready");
}
else
{
Serial.println("can't establish TCP connection");
}
String sendCmd = "AT+CIPSEND=";//determine the number of caracters to be sent.
Serial2.println(sendCmd);
delay(200);
Serial2.println(objlength);
delay(500);
if(Serial2.find(">"))
{
Serial.println("Sending..");
root.printTo(Serial2);
root.printTo(Serial);
//Serial.println(postRequest);
delay(2000);
if( Serial2.find("SEND OK"))
{
Serial.println("Packet sent");
delay(200);
while (Serial2.available()) {
String tmpResp = Serial2.readString();
Serial.println(tmpResp);
}
// close the connection
}
//delay(1000);
Serial2.print("+++");
delay(1200);
Serial2.println("AT+CIPCLOSE");
delay(50);
Serial.println("Closed");
}
}
Here's my node.js
var net = require('net');
var server = net.createServer(function(socket){
socket.write('SEND OK');
//
socket.pipe(socket);
socket.on('data',function(data){
//if(typeof data != 'string'){
var jsontest = JSON.parse(data);
console.log('Received: ' + data);
console.log(jsontest.weight);
console.log(jsontest.light);
console.log(jsontest.humid);
//}
});
socket.on('listening',function(){
console.log(listen);
});
});
/*server.getConnections(function(err,count){
console.log(count);
});*/
server.listen(1336, '10.42.0.1');
I think that esp8266 can establish a connection with a server , but I don't know why the data won't show. Maybe it's about esp8266 respond time?
screenshot
As you can see from this screenshot, I run node.js server and arduino ,but data won't show on server side. Due to this,I'm not sure where are the problems that cause this.
I'm not an expert. I'm just learning how to do it but i'd say you are not giving enough time through connections. You are relying on delays rather than timeouts while waiting for a true response. There is a difference.
Add much more time or change your strategy by using serial.available() and read in a loop that last a prudential amount of time, and exit when you got data.
Sorry no pasting some code, but i hope you got the idea.
Also i'm facing a power problem. 3,3v pin in arduino uno could be weak in clone boards. But i dont think that's the case.
I've got a MonoTouch app that does an HTTP POST with a 3.5MB file, and it is very unstable on the primary platforms that I test on (iPhone 3G with OS 3.1.2 and iPhone 4 with OS 4.2.1). I'll describe what I'm doing here and maybe someone can tell me if I'm doing something wrong.
In order to rule out the rest of my app, I've whittled this down to a tiny sample app. The app is an iPhone OpenGL Project and it does only this:
At startup, allocate 6MB of memory in 30k chunks. This simulates my app's memory usage.
Read a 3.5MB file into memory.
Create a thread to post the data. (Make a WebRequest object, use GetRequestStream(), and write the 3.5MB data in).
When the main thread detects that the posting thread is done, goto step 2 and repeat.
Also, each frame, I allocate 0-100k to simulate the app doing something. I don't keep any references to this data so it should be getting garbage collected.
iPhone 3G Result: The app gets through 6 to 8 uploads and then the OS kills it. There is no crash log, but there is a LowMemory log showing that the app was jettisoned.
iPhone 4 Result: It gets an Mprotect error around the 11th upload.
A few data points:
Instruments does NOT show the memory increasing as the app continues to upload.
Instruments doesn't show any significant leaks (maybe 1 kilobyte total).
It doesn't matter whether I write the post data in 64k chunks or all at once with one Stream.Write() call.
It doesn't matter whether I wait for a response (HttpWebRequest.HaveResponse) or not before starting the next upload.
It doesn't matter if the POST data is even valid. I've tried using valid POST data and I've tried sending 3MB of zeros.
If the app is not allocating any data each frame, then it takes longer to run out of memory (but as mentioned before, the memory that I'm allocating each frame is not referenced after the frame it was allocated on, so it should be scooped up by the GC).
If nobody has any ideas, I'll file a bug with Novell, but I wanted to see if I'm doing something wrong here first.
If anyone wants the full sample app, I can provide it, but I've pasted the contents of my EAGLView.cs below.
using System;
using System.Net;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using OpenTK.Platform.iPhoneOS;
using MonoTouch.CoreAnimation;
using OpenTK;
using OpenTK.Graphics.ES11;
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
using MonoTouch.OpenGLES;
namespace CrashTest
{
public partial class EAGLView : iPhoneOSGameView
{
[Export("layerClass")]
static Class LayerClass ()
{
return iPhoneOSGameView.GetLayerClass ();
}
[Export("initWithCoder:")]
public EAGLView (NSCoder coder) : base(coder)
{
LayerRetainsBacking = false;
LayerColorFormat = EAGLColorFormat.RGBA8;
ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
}
protected override void ConfigureLayer (CAEAGLLayer eaglLayer)
{
eaglLayer.Opaque = true;
}
protected override void OnRenderFrame (FrameEventArgs e)
{
SimulateAppAllocations();
UpdatePost();
base.OnRenderFrame (e);
float[] squareVertices = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
byte[] squareColors = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0,
0, 0, 255, 0, 255, 255 };
MakeCurrent ();
GL.Viewport (0, 0, Size.Width, Size.Height);
GL.MatrixMode (All.Projection);
GL.LoadIdentity ();
GL.Ortho (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
GL.MatrixMode (All.Modelview);
GL.Rotate (3.0f, 0.0f, 0.0f, 1.0f);
GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
GL.Clear ((uint)All.ColorBufferBit);
GL.VertexPointer (2, All.Float, 0, squareVertices);
GL.EnableClientState (All.VertexArray);
GL.ColorPointer (4, All.UnsignedByte, 0, squareColors);
GL.EnableClientState (All.ColorArray);
GL.DrawArrays (All.TriangleStrip, 0, 4);
SwapBuffers ();
}
AsyncHttpPost m_Post;
int m_nPosts = 1;
byte[] LoadPostData()
{
// Just return 3MB of zeros. It doesn't matter whether this is valid POST data or not.
return new byte[1024 * 1024 * 3];
}
void UpdatePost()
{
if ( m_Post == null || m_Post.PostStatus != AsyncHttpPostStatus.InProgress )
{
System.Console.WriteLine( string.Format( "Starting post {0}", m_nPosts++ ) );
byte [] postData = LoadPostData();
m_Post = new AsyncHttpPost(
"https://api-video.facebook.com/restserver.php",
"multipart/form-data; boundary=" + "8cdbcdf18ab6640",
postData );
}
}
Random m_Random = new Random(0);
List< byte [] > m_Allocations;
List< byte[] > m_InitialAllocations;
void SimulateAppAllocations()
{
// First time through, allocate a bunch of data that the app would allocate.
if ( m_InitialAllocations == null )
{
m_InitialAllocations = new List<byte[]>();
int nInitialBytes = 6 * 1024 * 1024;
int nBlockSize = 30000;
for ( int nCurBytes = 0; nCurBytes < nInitialBytes; nCurBytes += nBlockSize )
{
m_InitialAllocations.Add( new byte[nBlockSize] );
}
}
m_Allocations = new List<byte[]>();
for ( int i=0; i < 10; i++ )
{
int nAllocationSize = m_Random.Next( 10000 ) + 10;
m_Allocations.Add( new byte[nAllocationSize] );
}
}
}
public enum AsyncHttpPostStatus
{
InProgress,
Success,
Fail
}
public class AsyncHttpPost
{
public AsyncHttpPost( string sURL, string sContentType, byte [] postData )
{
m_PostData = postData;
m_PostStatus = AsyncHttpPostStatus.InProgress;
m_sContentType = sContentType;
m_sURL = sURL;
//UploadThread();
m_UploadThread = new Thread( new ThreadStart( UploadThread ) );
m_UploadThread.Start();
}
void UploadThread()
{
using ( MonoTouch.Foundation.NSAutoreleasePool pool = new MonoTouch.Foundation.NSAutoreleasePool() )
{
try
{
HttpWebRequest request = WebRequest.Create( m_sURL ) as HttpWebRequest;
request.Method = "POST";
request.ContentType = m_sContentType;
request.ContentLength = m_PostData.Length;
// Write the post data.
using ( Stream stream = request.GetRequestStream() )
{
stream.Write( m_PostData, 0, m_PostData.Length );
stream.Close();
}
System.Console.WriteLine( "Finished!" );
// We're done with the data now. Let it be garbage collected.
m_PostData = null;
// Finished!
m_PostStatus = AsyncHttpPostStatus.Success;
}
catch ( System.Exception e )
{
System.Console.WriteLine( "Error in AsyncHttpPost.UploadThread:\n" + e.Message );
m_PostStatus = AsyncHttpPostStatus.Fail;
}
}
}
public AsyncHttpPostStatus PostStatus
{
get
{
return m_PostStatus;
}
}
Thread m_UploadThread;
// Queued to be handled in the main thread.
byte [] m_PostData;
AsyncHttpPostStatus m_PostStatus;
string m_sContentType;
string m_sURL;
}
}
I think you should read in your file 1 KB (or some arbitrary size) at a time and write it to the web request.
Code similar to this:
byte[] buffer = new buffer[1024];
int bytesRead = 0;
using (FileStream fileStream = File.OpenRead("YourFile.txt"))
{
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
httpPostStream.Write(buffer, 0, bytesRead);
}
}
This is off the top of my head, but I think it's right.
This way you don't have an extra 3MB floating around in memory when you don't really need to. I think tricks like this are even more important on iDevices (or other devices) than on the desktop.
Test the buffer size too, a larger buffer will get you better speeds up to a point (I remember 8KB being pretty good).