simultanous read and write (stdin, stdout) in C - c

I'm trying to write a chat client and server and the client should be able to print the messeges from the server while also writing something on the console.
So I created a pthread that should read the user input and the main thread prints the messeges from the server. But when I type something and while typing a messege is received, the text I was typing is pushed up on the console. How can i fix that?
for example:
I'm typing "abcdef" and then when I get a messege from the server (but didn't finish typing yet) it will look like this:
abcdef[Chatuser1]:Hello

Use synchronization technique like semaphore or mutex to synchronize input and output in your multi threaded program

I would really recommend doing something like this in a GUI with two seperate edit box elements and not in a console.
If you still want to do it in a console, you will need to do direct console buffer modification.
Every time a new output message arrives, the current input message has to be backed up so you can savely write to the console then do some custom scrolling and add the input message back again. Thread syncronisation is needed to prevent mixing of input and output in the buffer.
I think you also would not get around custom key handling, because otherwise you have no access to partialy typed input.

Related

Delete current terminal input line

I am trying to code a little console chat-program in C on linux.
So far I coded it in a way that both chatting partners are only able to alternately send/recv, because these function calls are blocking by default.
Now I would like to modify that program, so that both are able to send and receive simultaneously.
The problem that I find is, that once you typed some input to the terminal, I don't know how to output received messages, without messing up the current input line of the terminal.
If there was a way to delete that current input line, you could temporarily save that line, print the new message and put the input line right back.
However, I was not able to find a solution for this problem on the internet.
Is it possible to delete the current input line, and if not, how else could I achieve what I want?
I think you should look into ncurses as Edd said in his comment.
It would allow you to easily manage contents in your terminal window, which sounds like a good idea for your chat program.
All you'd need to do is store your messages in 2 character arrays:
char incoming[MSG_MAX]
and
char outgoing[MSG_MAX]
Then you can output those messages wherever you want in your terminal window, since ncurses allows you to specify x,y coordinates on where to put your text.
Then a simple wrapper for one of ncurses erase() family functions would allow you to delete characters from specify x,y coordinates in your terminal window.
Edit: MSG_MAX is not an actual ncurses macro.

How to print what's on the command line C

To build a chat, I have to send and receive messages.
Currently, I am sending and receiving messages from the command line.
When I receive a message while I was typing one, the received message is printed and I can't see what was typed before. I use the read()command to catch the user input.
Here is an example:
Let's suppose I want to send the message Hello World and that I receive a message after typing Hello Wor.
This is what happens :
$ Enter your message : Hello Wor
$ Somebody: This is a message
$ Enter your message :
But Hello Wor is still on the command line: if I press the Delete Key, I will see Hello Wo.
This is what I want :
$ Enter your message : Hello Wor
$ Somebody: This is a message
$ Enter your message : Hello Wor
I would like to save what was typed before printing the received message and print it.
Without using a terminal control API like curses or ncurses, you will need to change your program to work like-so:
Disable local echo, so your program handles every local keypress before it's rendered by the caret in the terminal.
Your local keypress handling code will need to be asynchronous so it doesn't block on getchar while waiting for the user to enter the next character of their message or [Enter].
This is important so that your program can still run to collect and display messages received on the network end. While you could use a second thread for this it would mean two threads would be using stdio at the same time which is inadvisable, while you could use thread synchronization primitives to prevent this bug you're better-off using an asynchronous IO API instead.
Important note: "asynchronous" code does not mean "concurrent" nor does it imply the use of threading. In practice, it means the program's thread will return to a central dispatcher (cooperative yielding) instead of blocking on IO and the dispatcher will resume the function where it yielded when the IO operation completes (this is what the await keyword does in C# and JavaScript).
However, in C, working with the asynchronous terminal/console API in Linux is a PITA and you're better off using a library like ncurses which handles this for you.
When your program receives a message to display, you would clear the bottom line of the window (by overwriting it with whitespace or using VT100 ^[[2K), write the received message, then re-write the user's incomplete entered input (if any) on a new line.
Repeat.

Displaying terminal output of shell on client

I have 2 files Client Side & Server Side
I send a string over the socket from client to server. I have to execute this string as one does in a terminal. The output of the command is to be displayed on the client side.
Server Side Code : this loop runs on each thread created by pthread_create
while((n=recv(sock,client_message,2000,0))>0)
{
send(sock,server_out,n,0);
}
I need to run the string i recieve in client_message as a terminal command and fetch the output of the command and send it back via the server_out string buffer.
How do i go about this ?
So - you have two or three different tasks to accomplish.
The first one is to run the command line you received on the server. For that, you can start reading the system() function. It's very straightforward to use.
But then you need to get it's output. You can read about this two points in this question.
Lastly, send that data back to the server - once you have the output stream, it's just send()ing that via the socket. You can implement some mini-protocol for telling the other side how many bytes to expect, some error detection/correction if you want, etc.
Once the data arrives the client, then you can do whatever you want with it - print it on the screen, save to a file, you name it.
Read about this things, take your chances, and come back to continue asking if you need it - good luck!

Printf prints old buffer - C

I'm creating a server/client. The clent sends a message to the server, which stores it into a file. Than the client can read this message.
So, I'm using only the following functions (plus the bind etc): fgets, read (both for read from socket and file) write (to write on files/socket). And printf to print.
The strange thing is that when I call a printf, it happens that it prints an old text. So, for example if I decided to delete all the message, I'll receive from the server a string like "file deleted". Then in the following action, when there's a printf it happens that it prints the desider content plus a part of the previous pessage, like "file dele". How is this possible? What should I check in my code? I'd get things right without using things like fflush(stdout);.
You should check for proper '\0' termination.

Reprinting input to terminal in C

i am writing a terminal chat and would like to reprint the content the user has typed in, if a new message from another user has arrived asynchronously.
if a new message arrives i print "\x1B[2K" to stdout (ANSI ESCAPE CODE for erasing the current line) to clear the current line, then i print "\r" to move the cursor to the leftmost position, then i print the received message with a newline
now i would like to reprint the characters the user has typed - i found out that there is a special character VREPRINT (http://www.gnu.org/software/libc/manual/html_node/Editing-Characters.html) that can be used and if a hit CTRL-R it actually works... but if print the character to stdout using the character placed in c_cc[VREPRINT] of a struct termios, it does not work - is it even possible to do it that way?
I do not want to use any other libraries like readline or ncurses, since this would be plain overkill... i just would like to make my solution work using ICANON terminal mode if possible
Thanks in advance!
While it is possible to write to the same tty device that you are reading from, this doesn't mean that the characters that appear will be processed as input characters.
You can test this yourself, using two separate shell sessions (using screen, tmux, or, if you are on MacOSX, iTERM.app sessions).
in Session 1, get the current tty name:
tty
Let's assume the tty name of Session 1 is /dev/ttys000.
Then enter the following, without a return or newline -- just leave it pending:
echo abc def-
In Session 2 (using the tty name from Session 1), enter the following command:
echo foo >/dev/ttys000
The string foo should appear on the pending line in Session 1, like this:
echo abc def-foo
Now, go back to Session 1, and hit an "enter" (or return), causing the input buffer to be completed and sent to the shell, which will parse the first word as the echo command, with the subsequent arguments as text to be printed.
You should see the string "abc def-" echoed -- but not the foo.
This test makes it clear that the string foo was never placed into the input buffer, even though it was sent to the same tty being used for input (and output).
You can try to see if special control characters are recognized and processed; but they won't be. These characters are only being output to the terminal, but not processed.
In order for the special characters to be processed, they have to be received via the socket connected to the input device.
To accomplish what you are trying to do, you'll have to go non-canonical (stty -icanon) and process every character in your code, in order to collect the pending input and also be able to produce asynchronous output.
Alternatively, using nurses is not hard at all, and if you are writing a terminal-based chat program, I would suggest creating at least two panels: a "chat" panel for all output, and an "input" panel for user input. This allows output from other users, as well as the completed commands from the "input" panel, to be received and written to the "chat" panel asynchronously without disturbing the current command in progress by the user in the "input" panel.

Resources