I'm learning socket programming and there is a requirement in my project to put \r\n in every returned message. Something I notice that \r\n will delete the whole buffer when it exceeds some number of characters. For example, I have a code like this:
#include <iostream>
int main()
{
std::string message = "mkdir homewor";
const char *buffer = (message + "\r\n").c_str();
std::cout << "message: " << message << std::endl;
std::cout << "buffer: " << buffer << std::endl;
}
I run and it gives me the output like this:
message: mkdir homewor
buffer: mkdir homewor
I open the gdb and it gives me something like this:
message: "mkdir homewor"
buffer: 0x7fffffffdc50 "mkdir homewor\r\n"
- *buffer: 109 'm'
Which is something I expect it.
But when the message is too long and I convert it to C-String, the whole buffer gets deleted. For example:
#include <iostream>
int main()
{
std::string message = "mkdir homework"; // Just one more 'k' at the end
const char *buffer = (message + "\r\n").c_str();
std::cout << "message: " << message << std::endl;
std::cout << "buffer: " << buffer << std::endl;
}
I run and it gives me the output:
message: mkdir homework
buffer:
gdb gives me this:
message: "mkdir homework"
buffer: 0x55555556aeb0 ""
- *buffer: 0 '\000'
One more observation is that if the message has or exceeds the length of the message in the second example, the buffer will be deleted no matter what. Can anyone tell me what this problem is? I cannot get rid of \r\n because it's required in the project.
Thanks in advance.
(message + "\r\n") creates a new std::string, and it is backed with a pointer.
This new std::string will get destroyed at the end of the full-expression.
So you should do this,
#include <iostream>
int main()
{
std::string message = "mkdir homework"; // Just one more 'k' at the end
std::string messageSuffixed = message + "\r\n";
const char *buffer = messageSuffixed.c_str();
std::cout << "message: " << message << std::endl;
std::cout << "buffer: " << buffer << std::endl;
}
Related
I've been battling this code all day now, and I'm close to pulling what remains of my hair.
I've got a Server and Client class, and the original goal was for the Server class to have a list of 'Clients' with which it could interact. The entire host of issues aside, I've got some basics working. The Server does register new connections, and I can even send strings from the Client.
Here's the deal though, when I try to send a string with spaces, the whole thing breaks down.
Here's my Send function
int Send(std::string message)
{
const char* cstr = message.c_str();
size_t len = message.length();
//The +1 is for the \0 character that c_str() adds
//this->server is a socket that has already been connected to and accepted by the server
int bytes = send(this->server, cstr, len + 1, 0);
return bytes;
}
On the server side of things:
void Run()
{
char buffer[1024];
while (1)
{
listen(server, 0);
SOCKET incoming_sock;
int clientAddrSize = sizeof(clientAddr);
if ((incoming_sock = accept(server, (SOCKADDR*)&clientAddr, &clientAddrSize)) != INVALID_SOCKET)
{
std::cout << "Error: " << WSAGetLastError() << std::endl;
std::cout << "Connection occured " << printIP(clientAddr.sin_addr.s_addr) << std::endl;
int bytes = recv(incoming_sock, buffer, sizeof(buffer), 0);
std::cout << bytes << " Bytes With the message: " << buffer << std::endl;
std::cout << "Error: " << WSAGetLastError() << std::endl;
}
else
{
std::cout << "Error: " << WSAGetLastError() << std::endl;
}
}
}
Here's the weird part:
In my Client's main function, when I predefine a string, like "Hello World" the Server prints it out just fine. But when I try to parse user input with std::cin, the message breaks down after the first blank space.
Client Main Function:
#include "Client.h"
#include <iostream>
int main()
{
Client c("127.0.0.1", 5555, 1);
std::string msg = "Hello World!";
while (msg.compare("exit") != 0)
{
//std::cout << "Send: ";
//std::cin >> msg;
int bytes = c.Send(msg);
std::cout << "Sent \"" << msg << "\"" << "Bytes: " << bytes << std::endl;
}
while (1);
return 0;
}
And the Output on the Server:
In the Constructor Error code: 0Bind code: 0
Error: 0
Connection occured 127.0.0.0
13 Bytes With the message: Hello World!
Error: 0
If I uncomment the input, and type in "Hello" in the prompt, I get the following output:
In the Constructor Error code: 0Bind code: 0
Error: 0
Connection occured 127.0.0.0
6 Bytes With the message: hello
Error: 0
But if I type "Hello World!"
I only get:
In the Constructor Error code: 0Bind code: 0
Error: 0
Connection occured 127.0.0.0
6 Bytes With the message: Hello
Error: 0
std::cin >> msg; reads up to the first whitespace. If you want to read a full line up to the line-end character, make it
std::getline(cin, msg);
I have two processes. One writes to a file, one has to read from it (At the same time..). So there's two fstreams open at a given time for the file (Although they may be in different processes).
I wrote a simple test function to crudely implement the sort of functionality I need:
void test_file_access()
{
try {
std::string file_name = "/Users/xxxx/temp_test_folder/test_file.dat";
std::ofstream out(file_name,
std::ios_base::out | std::ios_base::app | std::ios_base::binary);
out.write("Hello\n", 7);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::array<char, 4096> read_buf;
std::ifstream in(file_name,
std::ios_base::in | std::ios_base::binary);
if (in.fail()) {
std::cout << "Error reading file" << std::endl;
return;
}
in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
//Exception at the below line.
in.read(read_buf.data(), read_buf.size());
auto last_read_size = in.gcount();
auto offset = in.tellg();
std::cout << "Read [" << read_buf.data() << "] from file. read_size = " << last_read_size
<< ", offset = " << offset << std::endl;
out.write("World\n", 7);
std::this_thread::sleep_for(std::chrono::seconds(1));
//Do this so I can continue from the position I was before?
//in.clear();
in.read(read_buf.data(), read_buf.size());
last_read_size = in.gcount();
offset = in.tellg();
std::cout << "Read [" << read_buf.data() << "] from file. read_size = " << last_read_size
<< ", offset = " << offset << std::endl;
//Remove if you don't have boost.
boost::filesystem::remove(file_name);
}
catch(std::ios_base::failure const & ex)
{
std::cout << "Error : " << ex.what() << std::endl;
std::cout << "System error : " << strerror(errno) << std::endl;
}
}
int main()
{
test_file_access();
}
Run, and the output is like this:
Error : ios_base::clear: unspecified iostream_category error
System error : Operation timed out
So two questions,
What is going wrong here? Why do I get an Operation timed out error?
Is this an incorrect attempt to do what I need to get done? If so, what are the problems here?
You write into this file 7 bytes, but then try to read 4096 bytes. So in stream will read only 7 bytes and throw an exception as requested. Note that if you catch this exception the rest of the code will be executed correctly, e.g. last_read_size will be 7 and you can access those 7 bytes in buffer.
I'm trying to implement a FUSE driver.
What I've done, is taken the basic operations that you override with your own function, and I've added a cout << operation << path << endl; So I can see which operation gets called. Here is my open function:
int Router::open(const char *path, struct fuse_file_info *fi) {
std::cout << "open " << path << std::endl;
return 0;
}
This returns 0 so the open should succeed all the time.
Then, here is my read function:
int Router::read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
std::cout << "read " << path << "Size: " << size << "Offset: " << offset << std::endl;
buf[0] = 'h';
buf[1] = '\0';
return 2;
}
This should copy over h\0 to the buffer.
But when I do: cat myfile it runs my open() function, which succeeds, then it runs my read() function, but the output of cat is nothing. It should output h but it doesn't. What am I doing wrong?
Also I find that under OSX, the exact same code only runs the open function, but never the read()
What could be the problem?
So my problem was that in the function: getattr(...) I did not specify the file size.
After doing: st->st_size = 4096; Everything was working fine :)
Hello I'm writing a short program to implement a shell and I'm running into an unusual problem. For some reason I can't clear to the std::cout buffer. The program wont print out messages. I understand a simple solution is to switch to std::cerr, but is there a way to get messages to print with cout?
Things I've tryed:
std::cout.flush()
Inserting std::endl after anything is written to standard out.
Inserting an std::flush into the output stream
std::cout.setf(std::ios::unitbuf); which was something I found that should unbuffer output.
Any help is much appreciated here is my code:
int main()
{
//Tryed this to unbuffer cout, no luck.
std::cout.setf(std::ios::unitbuf);
std::string input;
//Print out shell prompt and read in input from keyboard.
std::cout << "myshell> ";
std::getline(std::cin, input);
//**********************************************************************
//Step 1) Read in string and parse into tokens.
//**********************************************************************
char * buf = new char[input.length() + 1];
strcpy(buf, input.c_str());
int index = 0;
char * command[256];
command[index] = std::strtok(buf, " "); //Get first token.
std::cout << command[index] << std::endl;
while (command[index] != NULL)
{
++index;
command[index] = std::strtok(NULL," "); //Get remaining tokens.
std::cout << command[index] << std::endl;
}
std::cout.flush(); //No luck here either
//HERE IS WHERE MY PROBLEM IS.
std::cout << index << " items were added to the command array" << std::endl;
delete[] buf;
return 0;
}
The problem is that you're sending NULL to cout on the last iteration of the while loop, which leads to UB, and in your case is jamming cout. Check for NULL before you send anything to cout and you're fine:
if (command[index] != NULL) {
std::cout << command[index] << std::endl;
}
If you ever need to know what happened to your streams, remember that they can carry status information (the iostate, which I recommend you read about). The following code could have helped track your error:
try {
std::cout.exceptions(std::cout.failbit);
} catch(const std::ios_base::failure& e) {
std::cerr << "stream error: " << e.what() << std::endl;
std::cout.clear();
}
// continue working with cout, because std::cout.clear() removed
// failbit
Or, even simpler:
if(not std::cout) {
// address your error (if it is recoverable)
}
This is how your code would have looked like:
#include <cstring>
#include <string>
#include <iostream>
int main()
{
//Tryed this to unbuffer cout, no luck.
std::cout.setf(std::ios::unitbuf);
std::string input;
//Print out shell prompt and read in input from keyboard.
std::cout << "myshell> ";
std::getline(std::cin, input);
//**********************************************************************
//Step 1) Read in string and parse into tokens.
//**********************************************************************
char * buf = new char[input.length() + 1];
strcpy(buf, input.c_str());
int index = 0;
char * command[256];
command[index] = std::strtok(buf, " "); //Get first token.
std::cout << command[index] << std::endl;
while (command[index] != NULL)
{
++index;
command[index] = std::strtok(NULL," "); //Get remaining tokens.
std::cout << command[index] << std::endl;
}
// I added from here...
if(not std::cout) {
std::cerr << "cout is messed up... fixing it..." << std::endl;
std::cout.clear();
}
// ... to here.
std::cout.flush(); //No luck here either
//HERE IS WHERE MY PROBLEM IS.
std::cout << index << " items were added to the command array" << std::endl;
delete[] buf;
return 0;
}
Result:
$ ./a.out
myshell> 1 2 3
1
2
3
cout is messed up... fixing it...
3 items were added to the command array
I am sending
std::string cmdStr = "setxkbmap us";
int res = system( cmdStr.c_str() );
and the result is
res: 65280
What can be the problem?
That value indicates that the child process exited normally with a value of 255.
This could happen if:
/bin/sh couldn't find setxkbmap. (note: I might be wrong on this one. On my PC, /bin/sh returns 127 in that case.)
setxkbmap couldn't open the X server at $DISPLAY, including if DISPLAY is unset
I'm sure that there are many other possibilities. Check stdout for error messages.
When interpreting the return value from system on Linux, do this:
#include <sys/wait.h>
int res = system(foo);
if(WIFEXITED(res)) {
std::cout << "Normal exit: " << WEXITSTATUS(res) << "\n";
} else {
if(WIFSIGNALED(res)) {
std::cout << "Killed by signal #" << WTERMSIG(status);
if(WCOREDUMP(res)) {
std::cout << " Core dumped";
}
std::cout << "\n";
} else {
std::cout << "Unknown failure\n";
}
}