|
jschell wrote: Then it would in fact be international. You may notice that English is a well known and much used language in England. US trade with England is certainly international.
English is also a commonly used language in business between countries that have different national languages, but with English as a common language that they both (/all) understand.
If you really meant to say "If you are from the US and do not intend to have anything to do with anyone outside the US, or with anyone inside the US speaking other languages, being named or naming their businesses according to non-English conventions" - then abbreviating it to "English" is going much too far. The reader will think you are talking about the language, not a subset of trade with a single country.
You should be aware that there are lots of communities within the US of A where French or Spanish are commonly used languages. Their naming conventions often follows French/Spanish conventions as well.
Is there a federal law requiring all street names in the US to be written using A-Z only, with no strange accents? Does it apply e.g. within native reservations as well? Some of the native languages use completely different scripts, but when transcribed to Latin characters, you can see personal names using additional characters/accents. I do not know if that also goes for local place names within native reservations.
I have heard (no URL available) that in the old days, immigrants to the US of A carrying "strange" names that didn't fall naturally into the English language were forced to change their name. In some cases they were simply assigned a name with no relationship to their original name.
As far as I know, this is no longer the case. If you move to the US of A, you are allowed to keep your name - even if you settle in an English-speaking area. Even if your name contains characters outside of A-Z.
First be aware that I have been delivering internationalized products for decades. And then I fail to understand why you suggest to spend the effort of giving special treatment to speakers of one language within one country. Why not handle everyone, everywhere, the same way? Where is the gain of using 7-bit ASCII and nothing else to a subgroup of potential customers - especially considering that 7-bit ASCII is a true subset of UTF-8, so there is no expense in terms of space if your text is in fact limited to ASCII.
trønderen wrote:UTF-8 always could handle the entire Unicode range
So? That has nothing to do with what I said. And nothing to do with this thread. I allow myself to add to what you said. Just repeating your statements is meaningless.
This thread certainly has to do with which characters can be represented in various formats. Now that it is clear that the internal Java representation can not handle all Unicode characters, it is relevant to point out that UTF-8 can. I'd think that is is more relevant than to bring in, as you do, that communicating in English within a single current country can use even simpler codings.
Do you know that Java uses UTF-16 not UTF-8? That has been stated several times in this thread. If you want to be pedantic, it isn't 100% correct: Java uses a subset of UTF-16 that excludes surrogate pairs (and "variant selectors").
Some sources referenced in this discussion claim that UTF-16 at some point in time was "extended" to include surrogates. That is not true: UTF-16 was always designed to encode the entire Unicode character set (just like UTF-8). For a number of years, it seemed as if 65536 characters (the Basic Multilingual Plane, BMP) would be enough for everybody, so lots of coders (including the Java developers) gambled on surrogates never being required, treating Unicode as a 16 bit character set, period. I remember well when the first first "supplementary" characters where introduced, causing a big discussion which would be simpler: Going to an internal 32 bit representation, or be prepared for surrogates. What happened "at some point in time" is that a lot of programmers suddenly realized that they could no longer ignore the concept of surrogates.
I suspect - correct me if I am wrong - that the concept of "variant selector" was introduced into Unicode at a later point, long after UTF-16 including surrogates. If you can handle surrogates properly, then the step to handle variant selectors isn't that long. (Actually, it is longer if you went for a 32 bit internal working format!)
Note that there is a distinction between internal working format and external storage format. You certainly know that, but sometimes it seems as if you do not (want to) keep them strictly separate. Java character representation is an internal working format while a string is being temporarily processed in memory (just like the interernal working format in Windows). When you write
Just a general easy decision to make everything UTF in a database is not necessarily a good idea and there can be unexpected implications of making that decision Then you (note: you, not me) are moving out of the temporary internal working format domain. My comment about UTF-8 was given in that context. I am strongly in favor of storing all text in a database as UTF-8; certainly not as UTF-16.
Even though I have in fact delivered solutions on slower modems than that, it still has nothing to do with most business programming now. Consider it backgound information to explain to youngsters why a majority of Internet protocols (those based on RFC 822, 5322 today, which includes the majority of protocols seen by a user, such as SMTP, FTP, HTPP, SNMP for oldtimers ...) cannot handle even ISO 8859 - a fixed-size, 8 bit, extension of ASCII, the standard character set in 16-bit Windows. I bet that there are still *nix tool that stall if you give it ISO 8859 text!
I maintain that giving special attention to English when used in a limited context, the way you suggest, is a poor idea. Write all your software to always be prepared for non-ASCII characters, in any context - even when communicating in English with native English speakers within the US of A!
|
|
|
|
|
trønderen wrote: Java uses a subset of UTF-16 that excludes surrogate pairs
Ah...I wondered why your comments were so off base. No you are incorrect. It includes surrogate pairs. And it always has.
String (Java Platform SE 8 )[^]
"A String represents a string in the UTF-16 format in which supplementary characters are represented by surrogate pairs"
Matter of fact you can also use other languages in the code. Also something that has always been possible.
Java: Unicode in Source Code[^]
I am going to ignore the rest of your comments related to that since your initial assumption was wrong.
-----------------------------------------
trønderen wrote: You may notice that English is a well known...
As I already said, I have delivered internationalized products for decades.
And I have delivered products that were specifically limited to the United States. By their very nature.
trønderen wrote: 7-bit ASCII and nothing else to a subgroup of potential customers
Not sure exactly what you are referring to but I work in high volume applications. And thus the size of the data matters. Both on the wire and in storage.
And a lot of text even for international applications is not something that users see. So differentiating between the two is a design consideration.
trønderen wrote: storing all text in a database as UTF-8;
There are performance implications to doing that.
trønderen wrote: cannot handle even ISO 8859
And cars didn't have seat belts for decades. Hindsight means nothing.
trønderen wrote: Write all your software to always be prepared for non-ASCII characters, in any context
Absolutely not.
Just like I would not write an application to support 4 billion users just in case it might happen.
When I write software I get paid for writing it. Not for spinning endlessly about possibilities that very likely might never happen.
And I, perhaps unlike you, have worked on applications which would NEVER be used anywhere else. I am not going to detail that but consider if I had worked on a US defense contract for a nuclear missile. Do you think it will need to support the Russian language?
|
|
|
|
|
Maybe this will help. (Ranges and combining characters).
UnicodeRanges Class (System.Text.Unicode) | Microsoft Learn
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Hello, good day, I have 2 problems.
1. I can't find the installation path or the option mentioned in this post doesn't appear.
https://stackoverflow.com/questions/20718093/eclipse-interface-icons-very-small-on-high-resolution-screen-in-windows-8-1
2. Modifying the eclipse .ini file actually enlarges the icons but deconfigures my entire eclipse.
How can I solve it? Thank you.
|
|
|
|
|
Isn't there a forum somewhere where else (not this site) for Eclipse questions?
|
|
|
|
|
Any suggestions in Java for the following scenario:
Actually its truncating trailing zeros when converting to double.
Ex-1:
String - "123.4000"
double - 123.4000
Ex-2:
String - "123.4560"
double - 123.4560
|
|
|
|
|
Well, I do not see any truncation in your question. But most likely you misunderstand the difference between the string representation of a number and its actual value. For example the number 1.5 , can be presented as a string with a number of trailing zeroes such as: "1.50", "1.5000" etc. But its value is still 1.5 .
|
|
|
|
|
I understand that, i am getting input in form of string, the same need to be converted to double and send with out ignoring trailing zeros. I think now I am more clear on requirement.
|
|
|
|
|
Member 16135433 wrote: I think now I am more clear on requirement. Sorry, no you are not clear. What do you mean by "converted to double and send with out ignoring trailing zeros"? A double value, as I mentioned in my first reply, does not have trailing zeroes, it is just a number. How and where are you trying to send these numbers?
|
|
|
|
|
Quote: converted to double and send
No, not clear at all. What are you "sending" this data to?
All numerical types do not track trailing zeros, so whatever you're sending this data to must accept the values as strings, not a double type.
|
|
|
|
|
Member 16135433 wrote: the same need to be converted to double and send with out ignoring trailing zeros
Breaking that down into steps
1. String arrives
2. Convert to double
3. Something happens????
4. Then "send".
Unless something happens at step 3 which you did not define then of course you do not need to convert it in the first place.
That is because "send" in the modern world always means a string. XML, HTML, Json, even many other representations in TCP/IP will always be a string.
The only time when that is not true is when you are using a binary format and there can be all sorts for complications with that (precision, big versus, little, etc)
So presuming there is in fact a real need to handle it as a double then when you "send" it you must format it correctly. Just as though you started with a double in first place. In other words how it arrives is irrelevant.
|
|
|
|
|
|
There is no such thing as a value "with trailing zeros". "Trailing zeros" is a presentation thing, when you show the value in your UI, not a representation thing in a floating-point variable.
|
|
|
|
|
I found the following code posted by @Richard-MacCutchan to a thread about how to use JNI without having to add the location of jvm.dll into Environment Variables. I kinda understood how it works but still...
#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <filesystem> // requires -std:c++17
#include "jni.h"
HMODULE LoadDll(
const char* jrePath
)
{
const char* pszjvmname = "bin\\server\\jvm.dll"; HMODULE hJVMDLL = 0;
std::filesystem::path jvmpath(jrePath);
jvmpath /= pszjvmname;
if (!std::filesystem::exists(jvmpath))
{
std::cerr << "JVM library " << jvmpath << " not found." << std::endl;
}
hJVMDLL = LoadLibraryW(reinterpret_cast<PCWSTR>(jvmpath.c_str()));
if (hJVMDLL != NULL)
{
std::clog << "jvm.dll loaded from: " << jvmpath << std::endl;
}
return hJVMDLL; }
JNIEnv* AttachJVM(
const char* jrePath,
JavaVM* jvm,
std::string strcwd
)
{
HMODULE hJVMDLL = LoadDll(jrePath);
if (hJVMDLL == 0)
{
return nullptr;
}
typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");
JavaVMOption options[2];
std::stringstream ssoptions;
ssoptions << "-Djava.class.path=";
ssoptions << strcwd;
std::string stropts = ssoptions.str();
options[0].optionString = const_cast<char*>(stropts.c_str());
options[1].optionString = const_cast<char*>("-verbose:jni");
JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1; vm_args.ignoreUnrecognized = false;
vm_args.options = options;
for (int i = 0; i < vm_args.nOptions; ++i)
{
std::clog << "Options[" << i << "]: " << options[i].optionString << std::endl;
}
JNIEnv* env; jint res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res != 0)
{
std::cerr << "C++: JNI_CreateJavaVM returned: " << res << std::endl;
}
jint version = env->GetVersion();
std::clog << "JVM Version: " << (version >> 16) << "." << (version & 0xffff) << std::endl;
return env; }
void CallClass(
JNIEnv* jniEnv,
const char* pszClassname,
const char* pszMethodname,
const char* pszSignature
)
{
jclass jvmclass = jniEnv->FindClass(pszClassname);
if (jvmclass != NULL)
{
std::cout << "C++: Found the class: " << pszClassname << std::endl;
jmethodID jmid = jniEnv->GetStaticMethodID(jvmclass, pszMethodname, pszSignature);
if (jmid != NULL)
{
std::cout << "C++: Found the method: " << pszMethodname << std::endl;
jniEnv->CallStaticVoidMethod(jvmclass, jmid, NULL);
std::cout << "C++: env->CallStaticVoidMethod complete" << std::endl;
}
else
{
std::cerr << "C++: Failed to find the method: " << pszMethodname << std::endl;
}
}
else
{
std::cerr << "C++: Failed to find the class: " << pszClassname << std::endl;
}
}
int main(
int argc,
const char** argv
)
{
const char* jreDir = nullptr;
std::clog.setstate(std::ios::badbit);
for (argv++; argc > 1; ++argv, --argc)
{
if (*argv[0] == '-')
{
if (strstr(*argv, "-d"))
std::clog.clear();
}
else
{
jreDir = *argv;
}
}
if (jreDir == nullptr)
{
std::cerr << "No root path provided for JVM." << std::endl;
return 1;
}
JNIEnv* jniEnv = NULL;
std::filesystem::path cwd = std::filesystem::current_path();
JavaVM jvm;
jniEnv = AttachJVM(jreDir, &jvm, cwd.string());
if (jniEnv == NULL)
{
std::cerr << "C++: Failed to get Java environment" << std::endl;
return 1;
}
CallClass(jniEnv, "CppToJava", "main", "([Ljava/lang/String;)V");
jint jvmres = jvm.DestroyJavaVM(); std::clog << "C++: DestroyJavaVM and terminate: " << jvmres << std::endl;
}
I have two minor problems, I get a bit lost, I understand that it looks to see if Java in installed and tries to get the path to it and then to load the DLL, but I didn't managed to make it work for my situation, and also, on client machines I'm not making them install Java, but it comes in the app files with a license agreement, I'm using Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot).
If it isn't much to ask, could someone help me change the above code so that it will work in this scenario: Before creating the JVM, I'm running some other functions, and one of them returns the location for the app folder (ex: D:\Program Files\MyApp). Inside that folder are the apps data, and a folder Data, inside it a folder Java, and inside that all the java class files (...\MyApp\Data\Java\JavaMethods.class). So because I know the location of the app, I can give the location for jvm.dll by using the variable std::string location which would have as an example D:\Program Files\MyApp, then to that I can append \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server for the location of jvm.dll.
To be more precise, what I need to add before location.insert(0, "-Djava.class.path=");, to load the jvm.dll knowing it's location by combining like I said, the value from function parameter which would be set before calling the function and would have as an example D:\Program Files\MyApp, with \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server.
Here is an example how my app is using JNI extracted to a new project:
#include <jni.h>
#include <string>
#include <iostream>
#include <chrono>
#include <thread>
JavaVM* jvm = nullptr;
std::string createVM(std::string location) {
location.insert(0, "-Djava.class.path=");
location.append("Data\\Java");
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = &location[0];
vm_args.version = JNI_VERSION_10;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNIEnv* env = nullptr;
jint rc = JNI_OK;
if (jvm == nullptr) {
rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
else {
rc = jvm->AttachCurrentThread((void**)&env, NULL);
}
delete[] options;
if (rc != JNI_OK) {
if (rc == JNI_EVERSION)
return "JNI_EVERSION";
else if (rc == JNI_ENOMEM)
return "JNI_ENOMEM";
else if (rc == JNI_EINVAL)
return "JNI_EINVAL";
else if (rc == JNI_EEXIST)
return "JNI_EEXIST";
else
return "JNI_FATALERROR";
}
return "JNI_CREATED";
}
std::string createIdentification() {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
jclass jClass = env->FindClass("JavaMethods");
if (jClass == nullptr) {
return "ClassNotFound cI";
}
else {
jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
if (methodID == nullptr) {
return "MethodNotFound cI";
}
else {
jboolean isCopy;
jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
const char* string = env->GetStringUTFChars(jResult, &isCopy);
std::string result = string;
env->ReleaseStringUTFChars(jResult, string);
return result;
}
}
}
int main() {
std::cout << createVM("D:\\Program Files\\MyApp\\").c_str() << std::endl;
std::cout << createIdentification().c_str();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
return 0;
}
|
|
|
|
|
I managed to make it work:
#include <string>
#include <iostream>
#include <chrono>
#include <thread>
#include <jni.h>
#include <Windows.h>
JavaVM* jvm = nullptr;
std::string createVM(std::string location) {
std::string jvmLocation = location;
jvmLocation.append("ThirdParty\\Eclipse Adoptium\\jre-17.0.7.7-hotspot\\bin\\servers\\jvm.dll");
HMODULE hJVMDLL = LoadLibraryA(jvmLocation.c_str());
typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
if (hJVMDLL != NULL) {
fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");
location.insert(0, "-Djava.class.path=");
location.append("Data\\Java");
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = &location[0];
vm_args.version = JNI_VERSION_10;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNIEnv* env = nullptr;
jint rc = JNI_OK;
if (jvm == nullptr) {
rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
else {
rc = jvm->AttachCurrentThread((void**)&env, NULL);
}
delete[] options;
if (rc != JNI_OK) {
if (rc == JNI_EVERSION)
return "JNI_EVERSION";
else if (rc == JNI_ENOMEM)
return "JNI_ENOMEM";
else if (rc == JNI_EINVAL)
return "JNI_EINVAL";
else if (rc == JNI_EEXIST)
return "JNI_EEXIST";
else
return "JNI_FATALERROR";
}
return "JNI_CREATED";
}
else {
return "ERROR_LOADING_DLL";
}
}
std::string createIdentification() {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
jclass jClass = env->FindClass("JavaMethods");
if (jClass == nullptr) {
return "ClassNotFound cI";
}
else {
jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
if (methodID == nullptr) {
return "MethodNotFound cI";
}
else {
jboolean isCopy;
jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
const char* string = env->GetStringUTFChars(jResult, &isCopy);
std::string result = string;
env->ReleaseStringUTFChars(jResult, string);
return result;
}
}
}
int main() {
std::cout << createVM("Location_To_App_Folder").c_str() << std::endl;
if (jvm != NULL) {
std::cout << createIdentification().c_str();
}
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
return 0;
}
Thank you @Richard-MacCutchan for the original code!
|
|
|
|
|
Valentinor wrote: I'm not making them install Java
That is oddly phrased since they will need to have java installed somehow.
As a suggestion only you might want to work on your error handling if it turns out Java isn't installed. Telling a user that a dll is missing is not going to help them nor you when they ask why it isn't working. You might want to also print where you looked when you can't find it.
|
|
|
|
|
jschell wrote: That is oddly phrased since they will need to have java installed somehow.
Why did you stopped there with the quote? As the next part of the phrase contained the reason why I'm not making the install Java:
Valentinor wrote: but it comes in the app files with a license agreement, I'm using Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot).
So yeah, they don't need to install java, as it is included with the app.
|
|
|
|
|
Valentinor wrote: So yeah, they don't need to install java,
On Windows a Java install consists basically of the following.
1. Lay down the files into the file system.
2. Create the registry data so the user can uninstall it.
So apparently what you are actually doing is giving the user the option to use the Java that is already installed or to use the VM that comes with your application.
Besides my other suggestion you might also want to consider whether the VM they have installed is the correct version for your appliction.
|
|
|
|
|
jschell wrote: 1. Lay down the files into the file system.
Yes or no, depending what you mean by "file system". When the app is installed, inside it's folder structure it will also have Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot)
jschell wrote: 2. Create the registry data so the user can uninstall it.
It will be for the app itself and not just for java, as Eclipse Adoptium will be a part of the app, integrated into it, and not separate. When the app is uninstalled, so will Eclipse Adoptium as it is part of its files. If the user has any other form of Java installed, they won't be affected in any way.
jschell wrote: So apparently what you are actually doing is giving the user the option to use the Java that is already installed or to use the VM that comes with your application.
No. The app will only use Java that comes with it, as the app won't even look in another location if Java is installed, only inside it's file structure.
jschell wrote: whether the VM they have installed is the correct version for your appliction
I explained in the above statement why this doesn't matter for my case.
jschell wrote: As a suggestion only you might want to work on your error handling if it turns out Java isn't installed. Telling a user that a dll is missing is not going to help them nor you when they ask why it isn't working.
I never said that I don't have an error handling system already added. If any of Java files are missing or are corrupted, or any of the other app files are missing or are corrupted, an error will appear telling the user to run the check for corrupted files or reinstall the app, accompanied by an error message, that will tell me exactly which file is the problem, if it is missing or if it is corrupted.
|
|
|
|
|
I have a socket though which I'm sending files. If the file is under the buffer size (8192 in my case) then it is fine, but if the file is over that size, then when it writes to file, it writes the first chunk of 8192 bites every time. I'm using ObjectStream because beside the file, I'm sending other objects as well in the actual app, but this is the part of sending the file.
Client it sends the file data (testing):
System.out.println("Starting client");
Socket socket = new Socket("localhost", port);
System.out.println("Client sending data");
ObjectOutputStream dataOut = new ObjectOutputStream(socket.getOutputStream());
BufferedInputStream is = new BufferedInputStream(new FileInputStream(inFile));
byte[] buffer = new byte[8192];
int sizeRead = 0;
while ((sizeRead = is.read(buffer, 0, 8192)) >= 0) {
printByte(buffer, "in");
dataOut.writeObject(true);
dataOut.writeObject(buffer);
dataOut.writeObject(sizeRead);
dataOut.flush();
}
is.close();
System.out.println("Done sending file");
dataOut.writeObject(false);
socket.close();
System.out.println("Client closed");
Server that creates the file:
System.out.println("Starting server");
ServerSocket server = new ServerSocket(port);
System.out.println("Server waiting");
Socket socket = server.accept();
System.out.println("Client connected");
ObjectInputStream dataIn = new ObjectInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
Object auxKeepReading = dataIn.readObject();
if (auxKeepReading instanceof Boolean) {
while ((boolean) auxKeepReading) {
Object auxBuffer = dataIn.readObject();
if (!(auxBuffer instanceof byte[])) {
System.out.println("Broke byte");
break;
}
Object auxSize = dataIn.readObject();
if (!(auxSize instanceof Integer)) {
System.out.println("Broke int");
break;
}
printByte((byte[]) auxBuffer, "out");
bos.write((byte[]) auxBuffer, 0, (int) auxSize);
auxKeepReading = dataIn.readObject();
if (!(auxKeepReading instanceof Boolean)) {
System.out.println("Broke boolean");
break;
}
}
} else {
System.out.println("Broke boolean");
}
bos.close();
socket.close();
server.close();
System.out.println("Server stopped");
Why is it that it keeps sending the first chunk of byte[], and not what it reads new?
|
|
|
|
|
On client side after sending the size that it read, I added buffer = new byte[8192]; and now I don't have the problem and it is sending new data but there are 2 problems:
1. I don't know if this is what you should do;
2. The speed is limited to 3 MB/s when using IP instead of localhost, on an internet connection of 1.000 Mbps (~125 MB/s) upload/download (they are the same). I tried to increase the buffer size but still the same speed.
|
|
|
|
|
I was looking at this code earlier and wondered why you sent the buffer size after the data. It makes much more sense to send the size first. Also there is no point in sending 8192 bytes if you have only read one byte from the input file. So only send the amount of data that has been read. Tuning TCP performance is not an exact science unfortunately, but you can find plenty of discussions of the subject on the internet.
|
|
|
|
|
Richard MacCutchan wrote: I was looking at this code earlier and wondered why you sent the buffer size after the data. It makes much more sense to send the size first.
Because when they are used it doesn't matter the order they were sent, I didn't even think about that.
Richard MacCutchan wrote: Also there is no point in sending 8192 bytes if you have only read one byte from the input file. So only send the amount of data that has been read.
I changed that now on client: dataOut.writeObject(Arrays.copyOf(buffer, sizeRead));
What about buffer = new byte[8192]; I added, is that how it should be done to send now data each time?
dataOut.writeObject(true);
dataOut.writeObject(sizeRead);
dataOut.writeObject(Arrays.copyOf(buffer, sizeRead));
dataOut.flush();
buffer = new byte[8192];
Richard MacCutchan wrote: Tuning TCP performance is not an exact science unfortunately, but you can find plenty of discussions of the subject on the internet.
From what I've seen they suggest two things most of the time:
1. Setting socket.setTcpNoDelay(true); . I tried that on both client and server bust still no use;
2. Using BufferedOutputStream/BufferedInputStream inside ObjectOutputStream/ObjectInputStream, but still the same 3 MB/s. Even after combining 1. and 2.
|
|
|
|
|
JohnCodding wrote: What about buffer = new byte[8192]; I added, is that how it should be done to send now data each time? Yes, that is fine, as you allocate the buffer before you start the read/write loop. So each read from the input file will refill the same buffer. But I would be tempted to use ObjectOutputStream write(byte[](Java Platform SE 7 )[^], rather than writeObject , to send the byte data.
I have never had to do any TCP tuning so can't offer any useful suggestions, sorry.
|
|
|
|
|
Richard MacCutchan wrote: But I would be tempted to use ObjectOutputStream write(byte[](Java Platform SE 7 )[^], rather than writeObject, to send the byte data.
In the past when I used socket but not for files, I had some problems when I was using combination of ObjectOutputStream writeBoolean(), writeInt(), writeUTF(), writeObject(), the order was correct when writing/reading but I was still getting some exceptions, and when I switch to only writeObject() I didn't had any problems. And with objects I have more control over what the server gets from the client when the data is wrong, and shadow ban the IP if it keeps sending the wrong data based on some checks. As java class files can easily be decompiled, they can recreate the code and send part of the data good then wrong one just to be jerks or for phishing data. I have some checks on the server to know when someone clearly wasn't supposed to send data, and ignore it, and it did help.
Richard MacCutchan wrote: I have never had to do any TCP tuning so can't offer any useful suggestions, sorry.
Yeah, until now I didn't had problems, but now with files, also some that can be big, I do care about speed a lot. I'll keep looking and maybe I find a way to remove the limit. As there is clearly a limit because the speed stays around 3 MB/s and I did see someone complaining about the same exact speed, but there wasn't a solution on that thread.
|
|
|
|
|