I'm writing and reading a .txt file from a server using C# and .php file, below my C#
IEnumerator writeString()
{
string mycontent = "42.00 £3.80 sending test string";
url = "http://www.myServer.com/ewExternalFiles/writeScript.php?txt=" + mycontent;
WWW www = new WWW(url);
yield return www;
progress = www.progress;
while(progress < 1)
{
yield return null;
}
if (www.error == null)
{
Debug.Log("successfully written to server ..");
}
else
{
Debug.Log("Error! (" + www.error + ")");
}
}
My .php code
<?php
$txtcontent = $_REQUEST['txt'];
$fp = fopen("file.txt", w);
fwrite($fp, $txtcontent);
echo $fp;
fclose($fp);
?>
when reading it back all works fine, but if I change the line
string mycontent = "42.00 £3.80 sending test string";
to
string mycontent = "42.00% £3.80 sending test string";
I get the error
'Error! (400 Bad Request)'
from the server because of the % in the string, can I not have this in my string? Tanks.
URLs can only be sent over the Internet using the ASCII character-set.
Since URLs often contain characters outside the ASCII set, the URL has to be converted into a valid ASCII format.
string mycontent = WebUtility.UrlEncode("42.00% £3.80 sending test string");
The UrlEncode method is designed to receive a string and replaces unsafe ASCII characters with a "%" followed by two hexadecimal digits.
Related
I have the following upload code using Unity's UnityWebRequest API (Unity 2019.2.13f1):
public IEnumerator UploadJobFile(string jobId, string path)
{
if (!File.Exists(path))
{
Debug.LogError("The given file to upload does not exist. Please re-create the recording and try again.");
yield break;
}
UnityWebRequest upload = new UnityWebRequest(hostURL + "/jobs/upload/" + jobId);
upload.uploadHandler = new UploadHandlerFile(path);
upload.downloadHandler = new DownloadHandlerBuffer();
upload.method = UnityWebRequest.kHttpVerbPOST;
upload.SetRequestHeader("filename", Path.GetFileName(path));
UnityWebRequestAsyncOperation op = upload.SendWebRequest();
while (!upload.isDone)
{
//Debug.Log("Uploading file...");
Debug.Log("Uploading file. Progress " + (int)(upload.uploadProgress * 100f) + "%"); // <-----------------
yield return null;
}
if (upload.isNetworkError || upload.isHttpError)
{
Debug.LogError("Upload error:\n" + upload.error);
}
else
{
Debug.Log("Upload success");
}
// this is needed to clear resources on the file
upload.Dispose();
}
string hostURL = "http://localhost:8080";
string jobId = "manualUploadTest";
string path = "E:/Videos/short.mp4";
void Update()
{
if (Input.GetKeyDown(KeyCode.O))
{
Debug.Log("O key was pressed.");
StartCoroutine(UploadAndTest(jobId, path));
}
}
And the files I receive on the server side arrive broken, especially if they are larger (30 MB or more). They are missing bytes in the end and sometimes have entire byte blocks duplicated in the middle.
This happens both when testing client and server on the same machine or when running on different machines.
The server does not complain - from its perspective, no transport errors happened.
I noticed that if I comment out the access to upload.uploadProgress (and e.g. instead use the commented-out debug line above it which just prints a string literal), the files stay intact. Ditching the wile loop altogether and replacing it with yield return op also works.
I tested this strange behavior repeatedly in an outer loop - usually after at most 8 repetitions with the "faulty" code, the file appears broken. If I use the "correct" variant, 100 uploads (update: 500) in a row were successful.
Has upload.uploadProgress side-effects? For what it's worth, the same happens if I print op.progress instead - the files are also broken.
This sounds like a real bug. uploadProgress obviously should not have side effects.
I'm working on a project, where you have to retrieve data from a server and display it in the UI. It's a newsgroups server, that contains about 250 groups in total.
The output from the server SHOULD as far as I understand, be stored in a NetworkStream object and is read from a StreamReader which saves each line into a string.
This works, but unfortunately it seems like it doesn't finish reading everything before finishing the method call.
Next time I call another command and read it from the StreamReader it then returns the rest of the output from the previous command.
I've been struggling with this for hours now, and can't see how to fix this.
This is my code:
public ObservableCollection<Newsgroup> GetNewsGroups()
{
ObservableCollection<Newsgroup> newsgroups = new ObservableCollection<Newsgroup>();
if(connectionStatus.Equals(ConnectionStatus.CONNECTED) && loginStatus.Equals(LoginStatus.LOGGED_IN))
{
byte[] sendMessage = Encoding.UTF8.GetBytes("LIST\n");
// Write to the server
ns.Write(sendMessage, 0, sendMessage.Length);
Console.WriteLine("Sent {0} bytes to server...", sendMessage.Length);
ns.Flush();
// b) Read from the server
reader = new StreamReader(ns, Encoding.UTF8);
// We want to ignore the first line, as it just contains information about the data
string test = reader.ReadLine();
Console.WriteLine(test);
string recieveMessage = "";
if (ns.CanRead)
{
while (reader.Peek() >= 0)
{
recieveMessage = reader.ReadLine();
Console.WriteLine("Got this message {0} back from the server", recieveMessage);
// This part will simply remove the annoying numbers after the newsgroup name
int firstSpaceIndex = recieveMessage.IndexOf(" ");
string refactoredGroupName = recieveMessage.Substring(0, firstSpaceIndex);
newsgroups.Add(new Newsgroup { GroupName = refactoredGroupName });
}
}
}
return newsgroups;
}
I'd be interested to see what information about the data you are throwing away on the first line (what's in "test" variable). If it tells you how many bytes are coming your way, you should use that information to retrieve the correct amount of data instead of Peek.
If the last line contains a single period, change your while loop to look like this instead:
recieveMessage = reader.ReadLine();
while (recieveMessage != ".")
{
Console.WriteLine("Got this message {0} back from the server", recieveMessage); // This part will simply remove the annoying numbers after the newsgroup name int
firstSpaceIndex = recieveMessage.IndexOf(" ");
string refactoredGroupName = recieveMessage.Substring(0, firstSpaceIndex);
newsgroups.Add(new Newsgroup { GroupName = refactoredGroupName });
recieveMessage = reader.ReadLine();
}
So my project as of now is almost working:
It connects to facebook
It takes the Facebook ID and sends it to a script/iterator to handle connection
That script then sends off a concatenated string to a php url, which correctly checks my dataTable for an entry, and if not creates an entry
After that the php code echo's a text reply: OldUser/NewUserCreated/NewUserFailed
And here's where my problem starts:
the aim is to get the text from the echo, then check that string, if it works then unity moves on to the next scene and goes on, however when checking the string it fails for some reason, before I explain further here's my iterator that handles the connection:
IEnumerator Connect()
{
//call databasequeries and get sDBConnect
string sConnectPhp = GameObject.FindGameObjectWithTag("DBConnector").GetComponent<DatabaseQueries>().sDBConnect;
//now ready the url with the necessary code for php's get, and the FacebookID
string url = sConnectPhp + "?UserID=" + sFacebookID;
WWW wwwGet = new WWW(url);
yield return wwwGet;
string sTemp = wwwGet.text.ToString();
if(wwwGet.error == null)
{
print (sTemp);
if(sTemp == "OldUser")
{
//if successfully connected set to true
print ("connectToDatabase: successful");
bDatabaseConnected = true;
}
else if(sTemp == "NewUserCreated")
{
//if successfully connected set to true
print ("connectToDatabase: successful");
bDatabaseConnected = true;
}
else if(sTemp == "NewUserFailed")
{
//game connection has failed
print ("connectToDatabase: failed");
bDatabaseConnected = false;
bConnectionFailed = true;
}
}
else
{
//game connection has failed
print ("connectToDatabase: failed");
bDatabaseConnected = false;
bConnectionFailed = true;
}
}
Now my problem is that sTemp is printing in the unity console: OldUser, and it's not matching my if else condition? I have tried copying wwwGet.text without ToString but that doesn't work either - printing shows OldUser, but it doesn't match the condition
My only guess is that I haven't used ToString correctly, but my searches have shown it being used for Decimal and currency conversion, and as said without toString sTemp is not matching, any ideas as to why it's not matching?
I've been breaking my head over a bug in this system I've been building. Basically, I use sockets to communicate between two C# applications. Or rather a Unity C# script server and a C# client application.
With manual tests, the system works perfectly fine, no anomalies whatsoever.
In order to test performance and multi-user functionality, I wrote up a tester class which launches multiple threads(clients), and have those fire X amount of messages at the server. Here's where my problem occurs...Sometimes.
When a Socket sends or receives, it returns an integer container the amount of bytes that was sent/received. When the problem occurs, I can see that the correct amount of bytes arrived at the server. However, after putting the bytes into a string, suddenly I'm left with an empty string, instead of the message I'd normally see here.
I'm at a loss at to what's causing this problem. I'm using Encoding.Default.GetString() to translate the bytes into a string.
Any help is appreciated!
David
public void ReceiveFromClient (Socket handlerSocket)
{
serverBuffer = new byte[iBufferSize]; //iBufferSize = 8192;
int i = handlerSocket.Receive (serverBuffer);
Debug.Log ("Bytes received: " + i);
string message = Encoding.UTF8.GetString (serverBuffer, 0, i);
Debug.Log ("Message received: " + message);
//Do stuff with the message
}
bool SendMessageToUnity(string input)
{//returns a bool saying whether the message was sent or not
if (clientSocket != null)
{
if (clientSocket.Connected)
{
byte[] bytes = Encoding.UTF8.GetBytes(input+"|");
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending message: " + Encoding.UTF8.GetString(bytes) + Environment.NewLine)));
int i = clientSocket.Send(bytes);
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending "+i+" bytes. "+ Environment.NewLine)));
return true;
}
}
return false;
}
Look for for a zero value ('\0') in your array of bytes before converting it to a string.
private string GetString(byte[] data)
{
data = data.Where(b => b != 0).ToArray();
return Encoding.UTF8.GetString(data);
}
If you get the byte array correctly than the problem in the Encoding.
Check the sending Encoding usually UTF8 but you have to check it out.
and then var inputStr = Encoding.UTF8.GetString(InputByteArray);
^^
I have a ASP.Net web api which is intended to send a new file over the internet encoded as Base64. To do so, I have a public exposed REST service:
string imei = ControllerContext.Request.Headers.GetValues("IMEI").FirstOrDefault();
byte[] FileAsBytes = null;
String base64 = null;
var svcs = new CrudService.CrudServiceClient();
if (svcs.IsDeviceAccepted(imei))
{
FileAsBytes = svcs.DownloadSoftwareVersion();
}
if(FileAsBytes != null)
{
base64 = Convert.ToBase64String(FileAsBytes);
}
return base64;
and a Private service, CRUD service, which communicates directly with the database and the core layers.
After some debugging I found out that this service returns the correct lenght, something like 4194304 bytes, which seems to correspond to the size of file. However on the client side, I am contacting this service inside a AsyncTask:
#Override
protected String doInBackground(String... params) {
Log.i("UpdateManager: ", "Inside doInBackground");
try {
String imei = params[0];
String urlString = "http://10.118.18.50/Mobile.RESTPublicService/api/SoftwareUpdate";
HttpPost post = new HttpPost(urlString);
post.addHeader("IMEI", imei);
response = httpClient.execute(post);
Log.w("Update-Response: ",
Integer.toString(response.getStatusLine().getStatusCode())
+ " " + response.getStatusLine());
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
is = response.getEntity().getContent();
IOUtils.copy(is, writer, "UTF-8");
_log.debug(writer.toString());
Log.w("CONTENT: ", writer.toString());
byte[] result = new byte[MAX_FILE_SIZE]; //7242880 b
result = decodeBase64(writer.toString());
Log.w("BYTE ARRAY LENGTH: ", Integer.toString(result.length));
}
} catch (ClientProtocolException e) {
Log.e("Client: ", e.getMessage());
_log.error(e.getMessage());
return FAILED_DUE_TO_EXCEPTION;
} catch (IOException e) {
Log.e("IO: ", e.getMessage());
_log.error(e.getMessage());
return FAILED_DUE_TO_EXCEPTION;
}
return response.getStatusLine().toString();
}
The interesting point here is the result = decodeBase64(writer.toString()); and the decodeBase64 method:
protected byte[] decodeBase64(String s) {
return Base64.decode(s);
}
The String s is what I get from the webservice:
UEsDBBQACAgIAJteK0IAAAAAAAAAAAAAAAAZAAQAcmVzL2FuaW0vYWN0aXZpdHlmYWRlLnhtbP7KAABdkN9OwjAchc+PbW4YErnwgkRuuSGEek1MDI/SsMkmbF26es8D+AA+hs+hD6Wn0GXKab60/fq/ETK8CyCY4xNgL4TuCUPuyANZkEeyIXvySiaTqnGFbc1RO2MxHr9YU2+PbamRps5cWlmWv1ntKtNQ6ia3psqxXJbOtRul
This is not the whole file, but I can see that this is base64 encoded
When this string is passed inti the decodeBase64 method I only get this error message:
Then the application terminates. Is this the way to handle Base64 String? Can someone suggest how I can create a file from this base64 string? My first thought was to convert it to a byte array, and then create a file.
Looks to me like you've got a quoted string there - because " is what seems to be making it blow up. Is the web service returning a JSON string? If it is, then it will be surrounded by quotes and you have to take those off in order to parse it from base 64.