So, i am trying to make a c++ WinSock2 chatter, just for learning.
It is a console application and i want to take user input (for sending to the counterpart), but i still want to be able to recive. (so you can write a message while still being able to recive one)...
When using cin >> input; the program "pauses" until the user has enterd something, that way it is "turn based" (one user writes something and sends it, then the other user writes something and sends it).
Is there a way to make the user be able to write something WHILE the recive stuff is still running? (Preferably something else than multi threading)
What about checking if buffer isn't empty? But code wouldn't be really portable then, because you need to make some system calls as I know. See this.
But maybe you can do it with some C code, I'll do some research and update my answer.
UPD: Ok, I did it. What you need is select function.
It could wait till stdin is ready for read, and that's what we need.
But looks like it don't work with C++ streams, so you need to use only C code for reading.
Let's jump to definition:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
Ok, we need to check only read buffer, so writefds and errorfds could be NULL. And we need to check only stdin, so nfds is 1 (number of fdses)
What about timeout? It's should be 0, so we need to initialize variable struct timeval timeout and set seconds and nanoseconds to 0 by timeout.tv_sec = 0 and timeout.tv_usec = 0.
So, only readfds left. It's pretty simple too: we need to initialize variable, "zero" it, and add stdin.
It can be done with fd_set readfds, FD_ZERO(&readfds) and FD_SET(STDIN_FILENO, &readfds).
Okay, final step: function call. It should be select(1, &readfds, NULL, NULL, &timeout).
This would return 0 if input buffer is empty and 1 if it's not.
UPD2: Looks like it's not C++ streams, something strange happens and it breaks when buffer is empty at very first call. I'll try to catch the problem.
UPD3: Ok, Now I figured it out. Looks like you can use select with C++ streams.
Select has VERY strange (IMHO) feature: it resets readfds. I'm not sure how to prevent It from doing this, so I just used one more fd_set variable to hold it, so you need to add fd_set savefds = readfds after readfds initialization, and readfds = savefds after each call. That's awful solution, but I don't know how could I improve it.
So code is:
Initialization:
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
fd_set savefds = readfds;
Timeout initialization:
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
And usage:
if (select(1, &readfds, NULL, NULL, &timeout)) {
cin >> input;
send(input);
}
readfds = savefds;
UPD4: Don't forget to include unistd.h and cstdlib
The above answer is quite helpful.
Here is an example (base code taken from SELECT man page):
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int main(void)
{
fd_set rfds, save_rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Make a copy of rfds, as after running select, it gets reset */
save_rfds = rfds;
/* Wait for zero seconds. */
tv.tv_sec = 0;
tv.tv_usec = 0;
while(true){
retval = select(1, &rfds, NULL, NULL, &tv);
rfds = save_rfds;
if (retval == -1)
perror("select()");
else if (retval){
/* Runs as soon as you enter a value and press enter. */
std::cout<<"Data is available now.\n";
std::string s;
getline(std::cin, s);
std::cout<<"Data Input: "<<s<<"\n";
/* FD_ISSET(0, &rfds) will be true. */
}
}
exit(EXIT_SUCCESS);
}
Related
How could I possibly check if a Key is pressed on Windows?
As mentioned by others there's no cross platform way to do this, but on Windows you can do it like this:
The Code below checks if the key 'A' is down.
if(GetKeyState('A') & 0x8000/*Check if high-order bit is set (1 << 15)*/)
{
// Do stuff
}
In case of shift or similar you will need to pass one of these: https://msdn.microsoft.com/de-de/library/windows/desktop/dd375731(v=vs.85).aspx
if(GetKeyState(VK_SHIFT) & 0x8000)
{
// Shift down
}
The low-order bit indicates if key is toggled.
SHORT keyState = GetKeyState(VK_CAPITAL/*(caps lock)*/);
bool isToggled = keyState & 1;
bool isDown = keyState & 0x8000;
Oh and also don't forget to
#include <Windows.h>
Disclaimer: This answer was provided before the question was edited to limit its scope to a specific OS
There is no portable function that allows to check if a key is hit and continue if not. This is always system dependent.
Solution for linux and other posix compliant systems:
Here, for Morgan Mattews's code provide kbhit() functionality in a way compatible with any POSIX compliant system. He uses the trick of desactivating buffering at termios level.
Solution for windows:
For windows, Microsoft offers _kbhit()
check if a key is pressed, if yes, then do stuff
Consider 'select()', if this (reportedly Posix) function is available on your os.
'select()' uses 3 sets of bits, which you create using functions provided (see man select, FD_SET, etc). You probably only need create the input bits (for now)
from man page:
'select()' "allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform a corresponding I/O operation (e.g., read(2) without blocking...)"
When select is invoked:
a) the function looks at each fd identified in the sets, and if that fd state indicates you can do something (perhaps read, perhaps write), select will return and let you go do that ... 'all you got to do' is scan the bits, find the set bit, and take action on the fd associated with that bit.
The 1st set (passed into select) contains active input fd's (typically devices). Probably 1 bit in this set is all you will need. And with only 1 fd (i.e. an input from keyboard), 1 bit, this is all quite simple. With this return from select, you can 'do-stuff' (perhaps, after you have fetched the char).
b) the function also has a timeout, with which you identify how much time to await a change of the fd state. If the fd state does not change, the timeout will cause 'select()' to return with a 0. (i.e. no keyboard input) Your code can do something at this time, too, perhaps an output.
fyi - fd's are typically 0,1,2... Remembe that C uses 0 as STDIN, 1 and STDOUT.
Simple test set up: I open a terminal (separate from my console), and type the tty command in that terminal to find its id. The response is typically something like "/dev/pts/0", or 3, or 17...
Then I get an fd to use in 'select()' by using open:
// flag options are: O_RDONLY, O_WRONLY, or O_RDWR
int inFD = open( "/dev/pts/5", O_RDONLY );
It is useful to cout this value.
Here is a snippet to consider (from man select):
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n"); // i.e. doStuff()
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n"); // i.e. key not pressed
Are you talking about getchar function?
http://en.cppreference.com/w/c/io/getchar
This question already has answers here:
How to make reading from `std::cin` timeout after a particular amount of time
(5 answers)
Closed 4 years ago.
In C++ on OSX, how do we check std::cin for data without waiting?
The expected data is not coming from a keyboard or human, but from a program that has started my executable and talks to my executable via stdin. This 'parent' program will tell me to start a long process, may interrupt, and I may periodically send data back to it via stdout, therefore the checking of stdin must not block. I'm using XCode.
So far I have attempted to test via the following, neither of which seem to work:
//Return true if there is data waiting version 1
return (std::cin.peek() != EOF);
//Return true if there is data waiting version 2
return (std::cin.rdbuf() && std::cin.rdbuf()->in_avail() >= 0);
To fill out the idea mentioned in a comment, the easiest way since C++11 is simply to start a thread that waits for input and, when it is received, add it to a shared queue container. Doing so requires use of mutex locking & unlocking. This container then can be used to check if empty and, if it has something in it, the data can just be read and popped off of the front of the queue. Something like the following:
#include <thread>
#include <string>
#include <iostream>
std::mutex qmutex;
std::queue<std::string> queue;
void listen() {
std::string sin;
while (true) {
std::cin >> sin; // Thread will wait here for stdin to arrive
qmutex.lock();
queue.push(sin);
qmutex.unlock();
}
}
void mainstuff() {
std::thread t1(listen);
while (true) {
qmutex.lock();
if (!queue.empty()) {
//There's something in the queue, read it/take a copy
queue.pop();
}
qmutex.unlock();
// Respond to input
// Continue work
}
}
I don't believe cin supports non-blocking I/O operations or timeouts.
Here's an example of the lower-level way to accomplish the task, using select() and file descriptors. This program will immediately print to stdout any text it receives from stdin, and also wake up every 5 seconds (even if no text is received from stdin) just to print a fixed message. You can modify the wakeup timeout to whatever you like (including zero for an instantaneous-poll behavior), and/or add more file descriptors for it to react to if you prefer a more event-driven approach.
#include <stdio.h>
#include <sys/select.h>
static void RegisterFileDescriptor(int fd, int & maxFD, fd_set & fdset)
{
FD_SET(fd, &fdset);
if (fd > maxFD) maxFD = fd;
}
int main()
{
const int stdinFileno = fileno(stdin);
// This call is just here so that our parent process will immediately see any
// text lines that we print to stdout. If you're only reading from stdin and never
// writing responses back to stdout, then it's not really necessary.
(void) setlinebuf(stdout);
fd_set readSet;
while(true)
{
int maxFD = -1;
FD_ZERO(&readSet);
RegisterFileDescriptor(stdinFileno, maxFD, readSet);
// If you want to react to incoming data on any other
// file descriptors as well, you could call
// RegisterFileDescriptor on them here
struct timeval timeoutDelay = {5, 0}; // let's force a wakeup every 5 seconds
if (select(maxFD+1, &readSet, NULL, NULL, &timeoutDelay) < 0)
{
perror("select");
break;
}
printf("select() returned!\n");
if (FD_ISSET(stdinFileno, &readSet))
{
char buf[512];
if (fgets(buf, sizeof(buf), stdin)) printf("Read from stdin: [%s]\n", buf);
}
}
return 0;
}
I'm trying to multiplex an unnamed pipe with some other file descriptors.
The problem is that the pipe file descriptor always appears in the result of select. In other words the event-loop reads from pipe for infinite times. Here is a metaphor of what I want to do, and what actually happens.
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
int main(){
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
int fdmax; // maximum file descriptor number
int pfd[2];
if(pipe(pfd)!=0) {cout<<"Unable to create a pipe.\n",exit(1);};
FD_SET(0, &master);
FD_SET(pfd[0],&master);
fdmax=pfd[0];
if(fork()){//Parent
for (;;){
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
for(int i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
int n;
char buff[200];
if (i==pfd[0]){
close(pfd[1]);
n=read(pfd[0],buff,sizeof(buff));
buff[n]=0;
cout<<"Read from pipe:"<<buff<<endl;
}else if(i==0){
n=read(0,buff,sizeof(buff));
buff[n]=0;
cout<<"Read from std:"<<buff<<endl;
}
}
}
}
}else{//Child
usleep(50000);
char buff[200]="This is a simple sample.";
close(pfd[0]);
write(pfd[1],buff,sizeof(buff));
close(pfd[1]);
exit(0);
}
}
First of all, the read() call can read less than number of bytes specified in the last argument ant id does not automatically append zero-byte terminator, so your receiving code can easily access uninitialized memory in buff[] and after it (if there is no zero byte). You need to check return value when calling read and use only so many bytes from buffer.
Then, the select call returns when any file descriptor in the readfds set won't block on subsequent read. Which includes end-of-file condition. This likely happens in your case, when the forked process closes its fd. See this SO question too.
Could it be the reason for the problem you encounter? Checking return value when calling read make this clear to you, as read returns zero if-and-only-if the fd reached end of file.
Last detail – it does not make much sense to close pfd[1] only after pfd[0] is returned in the readfds. You should close it immediately after the fork, so it remains open in the child process only if you have no use for it in the parent process.
I'm sending some data trough the socket, but I need to set the timeout.
I'm using something like:
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sockDesc, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sockDesc + 1, &rfds, NULL, NULL, &tv);
if(rtn = ::recv(sockDesc, (raw_type*) buffer, bufferLen, 0)) < 0){
throw SocketException("error", true);
}
return rtn;
So.
Depending the type of data I return I need to implement timeout or not.
If I just send text data I don't need, if I send one file I need...
To explain more or less I'm sending some data through a socket and processing on the other side.
So, if I send one tar:
while(readtar){
senddata
get processed data
}
but sometimes the data sent is just the header, so when the other side process data it doesn't needs to return data and the socket stops on read.
To illustrate:
cat file.tar | myprogram -c "tar -zvt"
So it don't return nothing until receive enough data to return the name of file.
If i just send one file and returns the "cat" i dont have this problem
echo "asjdoiajdlaijdkasdjlkas" | myprogram -c "cat"
or
cat HUGEFILE.tar | myprogram -c "cat" | tar -zvt
In this case it does the same thing, but is not on the server side... so it dont work for me.
Now.... If I just use the recv without the select when I return the data using the cat it works... no problems with that.
BUT if I implement the select the data comes messed up.
WITHOUT SELECT
send "command line text temp test"
recv "command line text temp test"
WITH
send "command line text temp test"
recv "commmand lin/ˆ
1k5d99ck"
it's just to illustrate what is happening
Client loop:
while(size = read(fileno(stdin), thebuffer, 10000)){
sock->send(thebuffer, size); // if this data is not enough the other side never sends the data back
sock->recv //receive data
}
On the other side I do
if(pid == 0){
//stuffs closes, dup2
execlp("bash", "bash", "-c", "run.c_str(), NULL); // if i use one tar -zvt i need a bunch of data to generate the return
}
else
while(size = read(fout[0], buffer, 10000) > 0)){
sock->send(buffer, size);
}
So.. if the data sent is not enough to generate on
If I could check if read have anything or on the stdin side if the execlp send a terminator I could solve the problem
It sounds like you are expecting your TCP recv() to return data to you in chunks of a particular size... however, TCP recv() does not work that way. TCP is stream-based, so the number of bytes returned by recv() may vary anywhere between 1 (or 0 if you are using non-blocking I/O) and the size of the buffer you passed in. It's then up to your receiving code to loop as necessary to re-concatenate the received data again.
Also, it looks like you are trying to print out un-terminated ASCII strings -- that would explain the garbage characters at the end of your second recv() example. (i.e. if you want to print out the received data bytes as a string, be sure to place a NUL/0 byte after the last received byte; recv() won't do that for you)
I am using the following code to redirect stdout to a pipe, then read all the data from the pipe to a buffer. I have 2 problems:
first problem: when i send a string (after redirection) bigger then the pipe's BUFF_SIZE, the program stops responding (deadlock or something).
second problem: when i try to read from a pipe before something was sent to stdout. I get the same response, the program stops responding - _read command stuck's ...
The issue is that i don't know the amount of data that will be sent to the pipe after the redirection.
The first problem, i don't know how to handle and i'll be glad for help. The second problem i solved by a simple workaround, right after the redirection i print space character to stdout. but i guess that this solution is not the correct one ...
#include <fcntl.h>
#include <io.h>
#include <iostream>
#define READ 0
#define WRITE 1
#define BUFF_SIZE 5
using namespace std;
int main()
{
int stdout_pipe[2];
int saved_stdout;
saved_stdout = _dup(_fileno(stdout)); // save stdout
if(_pipe(stdout_pipe,BUFF_SIZE, O_TEXT) != 0 ) // make a pipe
{
exit(1);
}
fflush( stdout );
if(_dup2(stdout_pipe[1], _fileno(stdout)) != 0 ) //redirect stdout to the pipe
{
exit(1);
}
ios::sync_with_stdio();
setvbuf( stdout, NULL, _IONBF, 0 );
//anything sent to stdout goes now to the pipe
//printf(" ");//workaround for the second problem
printf("123456");//first problem
char buffer[BUFF_SIZE] = {0};
int nOutRead = 0;
nOutRead = _read(stdout_pipe[READ], buffer, BUFF_SIZE); //second problem
buffer[nOutRead] = '\0';
// reconnect stdout
if (_dup2(saved_stdout, _fileno(stdout)) != 0 )
{
exit(1);
}
ios::sync_with_stdio();
printf("buffer: %s\n", buffer);
}
Your problem is that you are using blocking I/O calls, while both ends of the pipe are connected to the same process. If you don't know how much data there will be, this is just a deadlock situation waiting to happen.
printf is a blocking call, which means that it will not return until all data has been written to the output device (the pipe in this case), or until a write error is signalled (for example, the other end of the pipe is closed).
_read works similarly. It only returns when it has a full buffer worth of data or it knows that the end of the input has been reached (which can be signalled by closing the write-end of the pipe).
The only ways around this are
to use non-blocking I/O (which is not feasible if you don't have access to the code that calls printf), or
to ensure the reading and writing happens in different processes or threads, or
to use a temporary file for buffering, instead of the buffer of a pipe.
Pipes are unidirectional. Ie. you can either write to a pipe (x)or you can read from it.
To simulate a pipeline, try the following (the below is C, not C++):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc)
{
int pfds[2];
pipe(pfds);
if (!fork()) {
close(1); /* close stdout, check for errors */
dup(pfds[1]); /* make stdout same as pfds[1], dup reuses lowest fd */
close(pfds[0]); /* not needed */
execlp("ls", "ls", NULL); /* or write() in whatever way you want */
} else {
close(0); /* close stdin, check for errors please! */
dup(pfds[0]); /* make stdin same as pfds[0] */
close(pfds[1]); /* not needed on this end */
execlp("wc", "wc", "-l", NULL); /* or read() */
}
return 0;
}
[edit] By the way, your code does not overflow a buffer. Its only relation to buffer overflow is that you're reading into a statically allocated array...if you read() more than sizeof buffer elements, then you'll run into problems.
You must use non-blocking I/O if you don't want read or write to be blocked in this case.