okay so i am trying to be more efficient in my programming, by attempting to pass multiple strings as one char array[100]. I can pass all this info from my client perfectly fine, but am now trying to use substr or strch to remove the values i passed using the char array on the server side.
server will look like this on the other end, with the data passed from the client being stored into memory under vel_rec:
recv(sock, vel_rec, 100, 0);
The program is set up to send some basic numerical data to a threaded server to run computations on and return results. I will most likely be using atoi function to get the integer values back out of the strings and then return a result back to the client. This returned result again will be a character array.
client:
char vel_snd[100], vel_rec[100], char buffer[100];
memset(buffer, 0, 99);
memset(vel_snd, 0, 99);
memset(vel_rec, 0, 99);
recv(sock, buffer, 100, 0);
//are we connected?
cout << "connection status = " << buffer << endl;
string v0, a, time, space = "\n", stop; stop = 'g';
while (stop != "x")
{
cout<<":::Press 'x' then 'enter' at any time to quit:::"<< endl;
cout<<"enter data? "<< endl;
cin>>v0;
stop = v0;
cout<<"some more data? "<<endl;
cin>>a;
stop = a;
cout<<"even more data? "<<endl;
cin>>time;
stop = time;
v0 += space + a + space + time;
strcpy(vel_snd, v0.c_str());
send(sock,vel_snd,strlen(vel_snd), 0);
cout<<"Calculating...\n";
recv(sock, vel_rec, 100, 0);
cout<<"\nThe data in "<<time<<" seconds will be "<<vel_rec<<endl;
}
okay so this is all fine and dandy, I am sure there exist infinitely better solutions to concatenation of the null characters which I am not even sure will work, just left them there for you to pick over if you can use them on the server side of things. I was attempting to use them to break out my original strings, but without success. I just want the server to receive this char array and copy sections of it into strings. I am assuming this is possible, but if not I could always send multiple char arrays through, it just seems to me that they would get jumbled up on the server if not properly flagged and organized as the data comes in. one in - one out, seems very clean to me and preferable honestly. The use of strings may not even be needed here as well, I just thought it would be better than using int values and converting, when i can just pass them as strings to begin with. Either way, I still need to implement some method of breaking out the values sent to the server from the client and the substr doesn't want to work with the char array.
I am also incredibly unfamiliar with anything networking and this is my first attempt at it from some tutorials i have seen. I had a 30 min lecture on the subject, with no further explanation other than "it works". That being said please be constructive in your responses. Hopefully I can learn a bit more than just this, since I plan on implementing something similar in a networked game I am working on. oh and before i forget this is using wsock32.lib.
recap:
[client]
char array1[100] = string 1 + string 2 + string 3
server<--char array1
char array2<--- server
print
[server]
char array1<---client string 1 + string 2 + string 3
int A = string 1
int B = string 2
int C = string 3
<some math...>
<char array 2 = itoa A B C>
client <--- char array2
Thanks a bunch
Shawn
Not sure I understood the question but a simple technique would be to for example, everytime the client enters something it will be newline terminated. Make the and when you have finished inputting data then send that message. When the message is then sent you automatically send the size of the array to the server. So for example on the server side:
char* temp;
int i=0;
nr=read(sd,buf,sizeof(buf));
temp = strtok(buf,"\n");
//Got the first token within the string.
//I'm pretending its an int to switch case the server
switch(i){
case 1:
temp = strtok(NULL,"\n");
//Get the next token
printf("CASE 1 with: %s",temp);
break;
}
etc...
I have not tested this code and just wrote it from the back of my mind so if there is faults in syntax I oppologize.
Good luck
suppose you store the received data in std::string received, then you can split it using this function:
std::vector<std::string> string_split(const std::string & str, char delim)
{
std::vector<std::string> elems;
std::stringstream strstream(str);
std::string item;
while(std::getline(strstream, item, delim))
elems.push_back(item);
return elems;
}
then call
std::vector<std::string> messages = string_split(received, '\n');
EDIT
Btw, you can replace this code
char vel_snd[100], vel_rec[100], char buffer[100];
memset(buffer, 0, 99);
memset(vel_snd, 0, 99);
memset(vel_rec, 0, 99);
with this code
char vel_snd[100] = {0}, vel_rec[100] = {0}, char buffer[100] = {0};
not exactly the same, but good enough when working with char arrays.
well i finally just broke down and sent separate char arrays each containing the necessary values to the multithreaded server, did atoi, did the calculations, stored the int calculated result back using itoa, and sent it back to the clients. Just needed to be smacked in the face with KISS. Tried making a gui to go with it in vs2010 but that was a headache, so switched to Qt, so i will be back with questions on that I am sure. Thanks for all the replies. I tried to vote, but I am too low on reputation.
Related
I have to make an http proxy. In the proxy side I have to parse the http request sent by the user.
The question is: How to read binary data from the client such at the final I will get an array of char that contains the full request .
What I did is: Read 1 Byte each time.
char c;
int n = read(con,&c,1);
I saw many implementation where we use 1024 bytes as the size of the buffer , but are we sure that the size of the request will not exceeds 1024?
Normally in first place I have to allocate the memory for the buffer array , so how can i know the size of the request to allocate the same size of memory?
My full methods:
void readToken(int con,char *token){
char c;
int i=0;
do{
int n = read(con,&c,1);
*token++ = c;
}while(c!=' ' && c!='\n');
}
void readLine(int con,char *line){
char c;int i=0;
do{
int n = read(con,&c,1);
*line++ = c;
}while(c!='\n');
}
char * handleRequest(int con){
char resource[30];
char version[5];
char method[4] ;
//i read 4 byte to get the method tyepe
int n = read(con,&method,4);
//here i read until i get a blank space
readToken(con,resource);
//readToken(con,version);
printf("the method is%s\n",method);
printf("the resource asked is%s\n",resource);
//printf("the resource asked is%s\n",version);
printf("the method read is %s",firstLine);
readLine(con,hostLine);
printf("the method read is %s",hostLine);
}
Reading by a single character is terribly inefficient and slows you down tremendously. Instead, you should be reading by chunks of approriate size (1024 seems as good initial guess as any) in the loop and append read buffer to the total data read so far. It is extremely easy to do with C++ std::vector.
Parsing an HTTP request is a quite complicated task, I think it could be easier to use a library like http-parser, which does the parsing for you in a very efficient way.
I'm currently working on a multiplayer game using sockets and I encountered some problems at the log-in.
Here's the server function - thread that deals with incoming messages from a user:
void Server::ClientThread(SOCKET Connection)
{
char *buffer = new char[256];
while (true)
{
ZeroMemory(buffer,256);
recv(Connection, buffer, 256, 0);
cout << buffer << endl;
if (strcmp(buffer, "StartLogIn"))
{
char* UserName = new char[256];
ZeroMemory(UserName, 256);
recv(Connection, UserName, 256, 0);
char* Password = new char[256];
ZeroMemory(Password, 256);
recv(Connection, Password, 256, 0);
cout << UserName << "-" << Password << " + "<< endl;
if (memcmp(UserName, "taigi100", sizeof(UserName)))
{
cout << "SMB Logged in";
}
else
cout << "Wrong UserName";
}
int error = send(Connection, "0", 1, 0);
// error = WSAGetLastError();
if (error == SOCKET_ERROR)
{
cout << "SMB D/Ced";
ExitThread(0);
}
}
}
And here is the function that sends the data from the client to the server:
if (LogInButton->isPressed())
{
send(Srv->getsConnect(), "StartLogIn", 256, 0);
const wchar_t* Usern = UserName->getText();
const wchar_t* Passn = Password->getText();
stringc aux = "";
aux += Usern;
char* User = (char*)aux.c_str();
stringc aux2 = "";
aux2 += Passn;
char* Pass = (char*)aux2.c_str();
if (strlen(User) > 0 && strlen(Pass) > 0)
{
send(Srv->getsConnect(), User, 256, 0);
send(Srv->getsConnect(), Pass, 256, 0);
}
}
I'm going to try to explain this as easy as possible. The first recv function from the while(true) in the Server-side function receives at first "StartLogIn" but does not enter the if only until the next loop of the while. Because it loops again it changes to "taigi100" ( a username I use ) and then it enters the if even tho it shouldn't.
A way to fix this would be to make a send-recv system in order to not send anything else until it got some feedback.
I want to know if there are any other fast ways of solving this problem and why such weird behaviour happens.
Well it's full of bugs.
Your overuse of new[]. Ok not a bug but you are not deleting any of these, and you could use either local stack buffer space or vector< char >
You need to always check the result of any call to recv as you are not guaranteed to receive the number of bytes you are expecting. The number you specify is the size of the buffer, not the number of bytes you are expecting to get.
strcmp returns 0 if the strings match, non-zero if they do not (actually 1 or -1 depending whether they compare less or greater). But it appears you are using non-zero to mean equal.
Not sure what stringc is. Some kind of conversion from wide string to string? In any case, I think send is const-correct so there is no need to cast the constness away.
3rd parameter of send is the number of bytes you are sending, not the capacity of your buffer. The user name and password are probably not 256 bytes. You need to send them as a "packet" though so the receiver knows what they are getting and will know when they have received a full packet. e.g. send a string like "User=vandamon\0". (And you need to check its return value too)
Because send() and recv() calls may not match up, two very good habits to get into are (1) preceed all variable length data by a fixed size length, and (2) only send the bare minimum needed.
So your initial send() call would be written as follows:
char const * const StartLogin = "StartLogIn";
short const StartLoginLength = static_cast<short>(strlen(StartLogin));
send(Srv->getsConnect(), reinterpret_cast<char *>(&StartLoginLength), sizeof(short), 0);
send(Srv->getsConnect(), StartLogin, StartLoginLength, 0);
The corresponding receive code would then have to read two bytes and guarantee that it got them by checking the return value from recv() and retrying if not enough was received. Then it would loop a second time reading exactly that many bytes into a buffer.
int guaranteedRecv(SOCKET s, char *buffer, int expected)
{
int totalReceived = 0;
int received;
while (totalReceived < expected)
{
received = recv(s, &buffer[totalReceived], expected - totalReceived, 0);
if (received <= 0)
{
// Handle errors
return -1;
}
totalReceived += received;
}
return totalReceived;
}
Note that this assumes a blocking socket. Non-blocking will return zero if no data is available and errno / WSAGetLastError() will say *WOULDBLOCK. If you want to go this route you'll have to handle this case specifically and find some way to block till data is available. Either that or busy-wait waiting for data, by repeatedly calling recv(). UGH.
Anyway, you call this first with the address of a short reinterpret_cast<char *> and expected == sizeof(short). Then you new[] enough space, and call a second time to get the payload. Beware of the lack of trailing NUL characters, unless you explicitly send them, which my code doesn't.
this is my first post. i am currently taking a networking class and i am required to write a client program that can download all emails from imap.gmail.com:993 to text files. i am required to write this program using winsock and openssl. I was able to connect to the server and fetch the emails. For emails with small data, i had no problem receiving it. But for emails with large data such as an images that is base64-decoded, i was able to download only a part of it.
so my question is How can i tell the client to wait until it received all the data from the server?
Here is what i have done so far:
void fetchMail(SSL *sslConnection,int lowerLimit, int UpperLimit)
{
SYSTEMTIME lt;
ofstream outfile;
GetLocalTime(<);
char szFile[MAX_PATH + 1];
char szPath[MAX_PATH+1];
char message[BUFSIZE];
char result[BUFSIZE];
::GetModuleFileName( NULL, szPath, MAX_PATH );
// Change file name to current full path
LPCTSTR psz = strchr( szPath, '\\');
if( psz != NULL )
{
szPath[psz-szPath] = '\0';
}
char szMailBox[MAX_PATH+1];
memset( szMailBox, 0, sizeof(szMailBox));
wsprintf( szMailBox, "%s\\inbox", szPath );
// Create a folder to store emails
::CreateDirectory( szMailBox, NULL );
for(int i = lowerLimit; i < UpperLimit; ++i)
{
// Create a folder to store emails
memset( szFile, 0, sizeof(szFile));
memset( result, 0, sizeof(result));
memset( message, 0, sizeof(message));
::sprintf(szFile,"%s\\%d%d%d%d%d%d.txt", szMailBox, lt.wHour, lt.wMinute,lt.wMinute,lt.wSecond, lt.wMilliseconds,i);
string Result;//string which will contain the result
stringstream convert; // stringstream used for the conversion
const char * num;
convert << i;//add the value of Number to the characters in the stream
Result = convert.str();//set Result to the content of the stream
num = Result.c_str();
strcpy(result, "tag FETCH ");
strcat(result, num);
strcat(result, " (BODY[TEXT])\r\n");
int n = 0;
cout << "\nFETCHING : \n";
SSL_write(sslConnection, result, strlen(result));
outfile.open(szFile );
SSL_read(sslConnection, message, sizeof(message)-1);
outfile <<message ;
outfile.close();
}
}
First of all some points on your code:
You use strcpy, strcat and all those unchecked, unsafe C functions. You might easily get buffer overflows and other kinds of errors. Consider to use C++ strings, vectors, arrays.
You do a lot of different things in that function, on different levels of abstraction. AFAICS only the two SSL_* function calls are really about fetching that mail. Consider to break out some functions to improve readability.
Now to your problem: Googling a bit about SSL_read, you will see that it returns an int, denoting how many bytes were actually read. You should use that return value - not only for this issue but also for error handling. If the mail data is longer than your buffer, the function will read until the buffer is filled and return its size. You should continue to call the function until all bytes have been read.
I am using a socket library (I'd rather not not use it) whose recv operations works with std::string, but is just a wrapper for one call of the recv socket function, so it is probably that I only got some part of the message I wanted. My first instinct was to go in a loop and append the received string to another string until I get everything, but this seems inefficient. Another possibility was to do the same with a char array, but this seems messy. (I'd have to check the strings size before adding into the array and if it overflowed I need to store the string somewhere until the array is empty again.. )
So I was thinking about using a stringstream. I use a TLV protocol, so I need to first extract two bytes into an unsigned short, then get a certain amount of bytes from the stringstream and then loop again until I reach a delimiter field.
Is there any better way to do this? Am I completely on the wrong track? Are there any best practices? So far I've always only seen direct use of the socket library with char arrays so I'm curious why using `std::string`` with stringstreams could be a bad idea..
Edit: Replying to the comment below: The library is one we use internally, its not public (its nothing special though, mostly just a wrapper around the socket library to add exceptions, etc.).
I should mention that I have a working prototype using the socket library directly.
This works something like:
int lengthFieldSize = sizeof(unsigned short);
int endOfBuffer= 0;//Pointer to last valid position in buffer.
while(true) {
char buffer[RCVBUFSIZE];
while(true) {
int offset= endOfBuffer;
int rs= 0;
rs= recv(sock, buffer+offset, sizeof(buffer)-offset, 0);
endOfBuffer+= rs;
if(rs < 1) {
// Received nothing or error.
break;
} else if(endOfBuffer == RCVBUFSIZE) {
// Buffer full.
break;
} else if(rs > 0 && endOfBuffer > 1) {
unsigned short msglength= 0;
memcpy((char *) &msglength, buffer+endOfBuffer-lengthFieldSize, lengthFieldSize);
if(msglength == 0) {
break; // Received a full transmission.
}
}
}
unsigned int startOfData = 0;
unsigned short protosize= 0;
while(true) {
// Copy first two bytes into protosize (length field)
memcpy((char *) &protosize, buffer+startOfData, lengthFieldSize);
// Is the last length field the delimiter?
// Then reply and return. (We're done.)
// Otherwise: Is the next message not completely in the buffer?
// Then break. (Outer while will take us back to receiving)
if(protosize == 0) {
// Done receiving. Now send:
SendReplyMsg(sock, lengthFieldSize);
// Clean up.
close(sock);
return;
} else if((endOfBuffer-lengthFieldSize-startOfData) < protosize) {
memmove(buffer, buffer+startOfData, RCVBUFSIZE-startOfData);
//Adjust endOfBuffer:
endOfBuffer-=startOfData;
break;
}
startOfData+= lengthFieldSize;
gtControl::gtMsg gtMessage;
if(!gtMessage.ParseFromArray(buffer+startOfData, protosize)) {
cerr << "Failed to parse gtMessage." << endl;
close(sock);
return;
}
// Move position pointer forward by one message (length+pbuf)
startOfData+= protosize;
PrintGtMessage(>Message);
}
}
So basically I have a big loop which contains a receiving loop and a parsing loop. There's a character array being passed back and forth as I can't be sure to have received everything until I actually parse it. I'm trying to replicate this behaviour using "proper" C++ (i.e. std::string)
My first instinct was to go in a loop and append the received string to another string until I get everything, but this seems inefficient.
String concatenation is technically platform dependent, but probably str1 + str2 will require one dynamic allocation and two copies (from str1 and str2). That's sorta slow, but it's far faster than network access! So my first piece of advice would be to go with your first instinct, to find out whether it's both correct and fast enough.
If it's not fast enough, and your profiler shows that the redundant string copies are to blame, consider maintaining a list of strings (std::vector<string*>, perhaps) and joining all the strings together once at the end. This requires some care, but should avoid a bunch of redundant string copying.
But definitely profile first!
My goal is create an app client server, written in C++.
When the server read an input from the client, should process the string and give an output.
Basically, I have a simply echo server that send the same message.
But if the user types a special string (like "quit"), the program have to do something else.
My problem is that this one dont happend, because the comparison between strings is not working... I dunno why!
Here a simple code:
while(1) {
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0);
send(client, buffer, num, 0);
char hello[6] ="hello";
if(strcmp(hello,buffer)==0) {
send(client, "hello dude! ", 12, 0);
}
buffer[num] = '\0';
if (buffer[num-1] == '\n')
buffer[num-1] = '\0';
std::cout << buffer;
strcpy(buffer, "");
}
Why the comparison is not working?
I have tried many solutions...but all failed :(
Your data in buf may not be NULL-terminated, because buf contains random data if not initialized. You only know the content of the first num bytes. Therefore you also have to check how much data you've received before comparing the strings:
const char hello[6] ="hello";
size_t hello_sz = sizeof hello - 1;
if(num == hello_sz && memcmp(hello, buffer, hello_sz) == 0) { ...
As a side note, this protocol will be fragile unless you delimit your messages, so in the event of fragmented reads (receive "hel" on first read, "lo" on the second) you can tell where one message starts and another one ends.
strcmp requires null terminated strings. The buffer you read to might have non-null characters after the received message.
Either right before the read do:
ZeroMemory(buffer, BUFSIZE); //or your compiler defined equivalent
Or right after the read
buffer[num] = '\0';
This will ensure that there is a terminating null at the end of the received message and the comparison should work.
A string is defined to be an array of chars upto and including the terminating \0 byte. Initially your buffer contains arbitrary bytes, and is not even guaranteed to contain a string. You have to set buffer[num] = '\0' to make it a string.
That of course means that recv should not read sizeof buffer bytes but one byte less.