I wrote a client-server chat for command line, but can't realise a beautiful input of messages in client part.
I create a thread, then I use fgets function with stdin stream to transmit messages to server. Then I print messages this way:
printf("Client -> Server: %s", fgets(&bufferData[0], sizeof(bufferData), stdin));
Input (server returns the message back):
Hello
Client -> Server: Hello
Server -> Client #500: Hello
I want to leave only last two lines.
If I do like that:
printf("Client -> Server: ");
fgets(&bufferData[0], sizeof(bufferData), stdin);
I get that:
Hey
Client -> Server: Server -> Client #456: Hey
How to make it just like that?
Client -> Server: Hey
Server -> Client #456: Hey
Client code with send realisation:
DWORD thID;
HANDLE hThread = CreateThread(NULL, NULL, HandleReadThread, (LPVOID)socketDescriptor, NULL, &thID);
printf("Client -> Server: ");
while (1)
{
fgets(&bufferData[0], sizeof(bufferData), stdin);
if (!strcmp(&bufferData[0], "quit\n"))
{
send(socketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0);
printf("You just left the chat. Good bye\n");
//break;
running = false;
int retwait = WaitForSingleObject(hThread, 500);
if (retwait == 0)
{
printf("WaitForSingleObject error : Error code: %d", GetLastError());
break;
}
if (shutdown(socketDescriptor, SD_BOTH) != 0)
{
printf("Shutdown SHUT_RDWR error");
}
break;
}
FD_ZERO(&writeSet);
FD_SET(socketDescriptor, &writeSet);
tv.tv_sec = 5;
if ((retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv)) == SOCKET_ERROR)
{
printf("Send non-blocking error");
break;
}
if (FD_ISSET(socketDescriptor, &writeSet) != 0)
{
if (send(socketDescriptor, bufferData, strlen(&bufferData[0]), 0) == SOCKET_ERROR)
{
printf("Send error");
break;
}
}
}
printf is buffered. You need to flush the buffer
printf(...)
fflush(stdout);
fgets(...)
Edit Note that fgets gets the newline. This needs to be removed before transmission.
Related
I've created my own SSH reverse tunnel using libssh by following the tutorials at http://api.libssh.org/master/libssh_tutorial.html and piecing things together from various other samples. However, now, all I get is the client echoing back whatever is inputted via the tunnel connection. I'm trying to get to the point where I can execute commands through the reverse tunnel (ex: ls -al).
The reverse tunnel (initiated on the client side):
int reverse_loop(ssh_session session){
ssh_channel channel;
int rc;
int nbytes, nwritten;
char buf[256];
int port = 0;
rc = ssh_channel_listen_forward(session, NULL, 43434, NULL);
if (rc != SSH_OK){
fprintf(stderr, "Error opening remote port %s\n", ssh_get_error(session));
return rc;
}
channel = ssh_channel_accept_forward(session, 60000, &port);
if (channel == NULL){
fprintf(stderr, "Error waiting for incoming connection: %s\n", ssh_get_error(session));
return SSH_ERROR;
}
while(1){
printf("In loop\n");
nbytes = ssh_channel_read(channel, buf, sizeof(buf), 0);
if (nbytes < 0){
fprintf(stderr, "Error reading incoming data: %s\n", ssh_get_error(session));
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("read channel\n");
if (nbytes > 0){
nwritten = ssh_channel_write(channel, buf, nbytes);
if (nwritten != nbytes){
fprintf(stderr, "Error sending answer: %s\n", ssh_get_error(session));
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("Wrote channel\n");
}
printf("sent answer!\n");
}
// close_channel
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_OK;
}
Running this, the reverse session is initiated. So, from the SSH server, I can run:
> nc localhost 43434
ls (this is what I sent)
ls (this is what I receive)
pwd (this is what I sent)
pwd (this is what I receive)
Then on the client side, I see this output:
In loop
read channel
Wrote channel
sent answer!
In loop
What I'm looking for are the actual results of running ls or pwd (or whatever system command the user inputs, not the echo. Can anyone direct me on the step that I missed to do this?
Thanks!
I am writing a simple server/client socket in C. The client asks the user to input a message and the server responds by repeating the same. The problem is when I send a message from the client the server responds back by appending extra character. How do I fix this.
This is my Client code
while(1) {
bzero(buffer, BUFSIZE);
printf("Enter Message: ");
scanf("%s", buffer);
//send some data
if(send(socket_fd, buffer, strlen(buffer), 0) <0) {
fprintf(stderr,"sending failed\n");
return 1;
}
//receive a reply from the server
if(recv(socket_fd, server_reply, BUFSIZE,0)<0)
{
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
}
This is my server code
int read_size;
while((read_size = recv(client_socket_fd, buffer, BUFSIZE,0))>0)
{
// Reply back to the client
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
fprintf(stderr, "could not write back to socket\n");
} else {
fprintf(stdout, "message back to client\n");
}
}
if(read_size==0)
{
fprintf(stderr,"disconnected.\n");
fflush(stdout);
}
else if(read_size==-1){
fprintf(stderr, "error.\n");
}
This is the output
Enter Message: welcome
Reply: welcome
Enter Message: hello
Reply: hellome
Enter Message: hi
Reply: hillome
You need a string in order to use strlen(). Your arrays are not strings, rely on read_size instead for the length of the buffer.
Strings in c are just a sequence of printable characters followed by a '\0', and none of your arrays has any '\0' so strlen() is causing undefined behavior. The strlen() function actually scans the string until it finds the '\0' and in the process it counts how many characters were there.
#Iharob's answer is correct. Basically, change the line:
write(client_socket_fd, buffer, strlen(buffer))
to:
write(client_socket_fd, buffer, read_size)
It isn't. You are printing junk at the end of your buffer. You're also ignoring end of stream.
if(recv(socket_fd, server_reply, BUFSIZE,0)<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
should be
int count;
if((count = recv(socket_fd, server_reply, BUFSIZE,0))<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
else if (count == 0) {
// EOS
fprintf(stderr, "peer has disconnected.\n");
break;
} else {
fprintf(stdout, "Reply: %.*s\n ", count, servreply);
}
Your 'write back to the client' is also incorrect:
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
should be
if (0 > write(client_socket_fd, buffer, read_size)) {
I am having a printing issue with my server. I want there to be simultaneous printing when I have 2 or more clients active on terminals. However, I am only printing from one client at a time. Once I close a client, the other clients are free to write to the server. What can I do to fix my problem?
I have tried to fork the printing section, which I think didn't really do anything. (Just realized if I do this, then the select system call is a waste, i'd rather use the select system call) *edit
while(TRUE) {
FD_ZERO(&readfds);
FD_SET(socket1, &readfds);
FD_SET(socket2, &readfds);
FD_SET(socket3, &readfds);
select(socket3+1, &readfds, NULL, NULL, NULL);
//add socket1
if(FD_ISSET(socket1, &readfds)) {
if((client_socket1 = accept(socket1, NULL, NULL)) < 0) {
perror("accept1");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message1 sent successfully\n");
}
//add socket2
if(FD_ISSET(socket2, &readfds)) {
if((client_socket2 = accept(socket2, (struct sockaddr *)&addr2, (socklen_t*)&addr2)) < 0) {
perror("accept2");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message2 sent successfully\n");
}
//add socket 3
if(FD_ISSET(socket3, &readfds)) {
if((client_socket3 = accept(socket3, (struct sockaddr *)&addr3, (socklen_t*)&addr3)) < 0) {
perror("accept3");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message3 sent successfully\n");
}
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 2
while( (ready = read(client_socket2, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 1
while( (ready = read(client_socket1, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
}
You need to add your client sockets to the fd_set and select statement before attempting to read from them. Also, you should make all your sockets non-blocking. Otherwise, the read call will block until you get data.
Here's a quick fix that uses recv instead of read to read the sockets, but with the async flag of MSG_DONTWAIT.
I didn't see anywhere where you were closing your client sockets or handling errors properly. So I inserted some code as a hint. Also, it's never a good idea to "printf" a buffer of data from a socket directly. Because you never know if the data you received is null terminated. Always null terminate your buffer after you read the data off the socket.
Change this block of code:
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
To this:
while (1)
{
int result;
result = recv(client_socket3, buffer, sizeof(buffer)-1, MSG_DONTWAIT);
if ((result == -1) &&
((errno == EAGAIN) || (errno==EWOULDBLOCK)) )
{
// no more data available, but could be available later
// use the socket with "select" above to wait for more data
}
else if ((result == -1) || (result == 0))
{
// remote close or unrecoverable error
close(client_socket3);
client_socket3=-1;
}
else
{
// null terminate the buffer before printing
buffer[result] = '\0';
printf("%s\n", buffer);
}
}
I want to find a way to exit from the "loop in question" (see below) with keeping the program running, I mean : In the program there must be the message: "preparing to send informations, exit to stop !" if the user doesn't type exit, the program must still running without waiting the user to click in a character and then enter. The informations must be sent continuously until the user type exit to quit the program.
I hope I explain well the problem, and I'm sure that there is an easy solution
Thank you in advance for your help
do
{
/* menu */
printf("\r\n");
printf("1 : Start, Sending Informations.\r\n");
printf("2 : Quit.\r\n");
printf("choice : ");
scanf("%d", &nChoice);
printf("\n Trying to do a connection \n \r");
/* if connection is not established, call accept, TCP SERVER */
if (fd_client == -1)
{
printf("ready to accept...\n");
fd_client = accept(fd_listen, (struct sockaddr*)&client_addr, &addrlen);
if (fd_client >= 0)
{
printf("accept: %s, port %d\r\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
}
}
if (fd_client < 0)
{
printf(" connection is not established, continue to accept\n");
/*connection is not established, continue to accept*/
continue;
}
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(fd_tty, &rfd);
FD_SET(fd_client, &rfd);
maxfd = (fd_tty > fd_client ? fd_tty : fd_client) + 1;
/*connection is established, call select to see if any data arrived from the GPS*/
printf("connection is established, seeing if any data arrived\n");
char chaine1[256];
char chaine2[] = "exit";
int i;
if (nChoice == 1)
{
do // THE LOOP IN QUESTION
{
printf("preparing to send informations, exit to stop !\n");
i = strcmp(chaine1, chaine2); // Building the condition to exit
scanf("%s", chaine1);
fflush(stdin);
// printf ("i= %d\n",i);
ret = select(maxfd, &rfd, &wfd, &efd, &tm);
if (ret < 0) // Select failed
{
printf("select fail\r\n");
break;
}
else if (ret == 0)
{
continue; /*no data arrived, continue to call select*/
}
else
printf("data is arriving \n");
if (FD_ISSET(fd_tty, &rfd)) /*tty port has data to be read*/
{
ret = read(fd_tty, buf, sizeof(buf));
if (ret <= 0)
{
printf("read tty port fail\r\n");
break;
}
if (send(fd_client, buf, ret, 0) < 0) /*send data to ethernet*/
{
printf("send to ethernet fail\r\n");
break;
}
}
if (FD_ISSET(fd_client, &rfd)) /*tcp client has data to be read*/
{
ret = recv(fd_client, buf, sizeof(buf), 0);
if (ret < 0)
{
printf("read from ethernet fail\r\n");
break;
}
else if (ret == 0)
{
printf("disconnect by remote\r\n");
close(fd_client);
fd_client = -1;
continue; /*continue to accept...*/
}
if (write(fd_tty, buf, ret) < 0) /*send data to tty port*/
{
printf("write to tty fail\r\n");
break;
}
}
} while (i != 0 ); // The exit condition
}
} while(nChoice != 2);
Simple thing you can do is to wait for a timeout. But with scanf you can't do that so you can go for a select() call for the event at stdin and proceed if no event within that time.
Please check the following link
http://cboard.cprogramming.com/c-programming/96544-unblock-scanf-call.html
Hope this helps.
i think it should be noted that fflush(); is designed for output streams and is undefined when used on input streams, 1 way to get around the problem would be scanf(" %s", chaine1); or create a function to clear input buffer.
I am trying to create a server and client program that sends a string from client to server where the server executes that string and sends the output back to the client. I am doing this in linux and I am very confused why my program isnt working the least bit. Here is the code.
**Client**
int main()
{
//Code to use unix socket here
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
}
done=0;
do {
if(t=recv(s, str, MAX, 0)<0)
perror("recv failed at client side!\n");
str[t] = '\0';
if(strcmp(str, "ENDOFTRANS")==0)
{
printf("\nRead ENDOFTRANS. Breaking loop.\n");
done=1;
}
printf("Server > %s", str);
} while(!done);
}
And then the server code is:
**Server**
#define MAX 1000
int main(void)
{
//Unix socket code
//This process is now a daemon.
daemon();
//Listens for client connections, up to 5 clients can queue up at the same time.
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n, status;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
switch(fork())
{
case -1: //ERROR
perror("Could not fork.\n");
break;
case 0: //CHILD
//Accept string from client.
//Edit: Why am I getting an error here? says: Invalid argument.
if(n = recv(newsock, str, MAX, 0)) {
perror("Recv error at server side.\n");
exit(1);
}
str[n]='\0';
if (n <= 0) {
if (n < 0)
perror("recv");
done = 1;
}
printf("String=>%s<",str);
//Redirect socket to STDOUT & STDERR.
test = close(WRITE); assert(test==0);
test = dup(newsock); assert(test==WRITE);
test = close(ERROR); assert(test==0);
test = dup(newsock); assert(test==ERROR);
if (!done)
{
if (str==something)
{
//execute command
}
else {
//Fork and execvp the command
}
//Sends End of Transaction character.
ENDTHETRANS();
exit(0);
}
break;
default: //PARENT
//Parent keeps accepting further clients.
wait(&status);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done=1;
break;
}
} while (!done);
}
close(s);
}
Im relatively new to programming in general and from my understanding the client code is good except that when it recieves the text back from the server it only recieves the text in small bits (2 rows at a time). I have to keep pressing enter on client promt to get the rest of the input. I have tried so many things that by this point I dont even know what I am doing wrong anymore.
Firstly, in the server code, after it recieves the string from the client I have a printf("String=>%s<",str); that outputs the string. However when the server prints the output as String=>ls -l the < key at the end gets eaten up somehow. It shouldnt be doing that right?
Any help much appreciated. Please bare in mind that I am a beginner and have only used pipes as inter process communcation before. Now I wanna make my first unix socket program.
Thanks in advance.
The usual problem in cases such as this is not realizing that SOCK_STREAM sockets don't preserve message boundaries. So data sent with a send call might be split up and received in multiple recvs, or it might be coalesced and multiple sends end up in a single recv. Most importantly, when a kernel send buffer fills up, a send call might write partial data (sending only some of the requested data) and return a short return value. You need to test for this and resend the rest of the data.
Another problem that often shows up is issues with line endings (particularly when talking between linux and windows). There may be extra carriage return characters (\r) in the either the client or server that confuse the other side. These tend to result in apparently missing or truncated output when printed.
edit
The line
if(t=recv(s, str, MAX, 0)<0)
is equivalent to
if(t = (recv(s, str, MAX, 0)<0))
that is, it sets t to 0 or 1 depending on whether there was an error or not. As with most errors of this type, turning on warnings will give you some indication about it.