I've got a basic linux socket program mostly running that accepts strings from the client to send to the server. When "quit" is typed, my client program ends, but the server one prints out "quit" endlessly until you kill the program. Either I'm not reading the string properly or my logic is off.
Code section...
while (1)
{
//fetch message from client and write to stdout
num_client_bytes = recv(client_sockfd, buf, LEN, 0);
if (-1 == num_client_bytes)
{
perror("server-- recv failed");
}
else
{
printf("client msg: %s", buf);
if (0 == strcmp(buf, "quit\n"))
{
break;
}
}
}
//remove local socket file and close sockets
unlink(SOCKET_NAME);
close(client_sockfd);
close(server_sockfd);
return 0;
You need to memset buf prior to recv
recv will not add '\0' at the end of string read from socket,
also you should check if recv read entire 4 bytes, then change:
strcmp(buf, "quit\n")
to
strncmp(buf, "quit\n",4)// if you are not sure client sends \n
Related
I was trying to send "-1" as an indicator from the server to the client using send() function, however the recv() function at the client side keeps receiving only 1 byte of the data (the return of recv() is 1).
Code
Server-side:
get_fd(buf, fd, stat_buf) gets a file descriptor based on the number in buf and returns -1 if the number in buf is invalid 0 if everything works fine.
if(get_fd(buf, fd, stat_buf) == -1){ // invalid file number
printf("client has given an invalid file number\n\n");
if(send(new_sockfd, "-1", 3, 0) == -1){
perror("client: send");
}
close(new_sockfd);
exit(1);
} else { // valid file number
/* code */
}
When I entered an invalid file number at the client-side, the printf() on the second line works fine and no perror() message has been seen.
Client-side:
std::memset(&buf, 0, MAXDATASIZE); // clear the buffer for it has been used previously
if((numbyte = recv(sockfd, buf, MAXDATASIZE-1, 0))==-1){
perror("client: recv");
exit(1);
}
buf[numbyte] = '\0';
printf("numbyte: %d, received: %s\n\n", numbyte, buf);
The numbyte is always 1, while printf() prints nothing for the buf as string, but when printing the buf as an int (%d) it prints a nonsense negative number, for example -333179216.
The problem was at the beginning of the connection when the server sends ( send() ) the first message to the client. You set the len to a number that is much larger than its actual length. It works fine in the beginning because there are no more communications, but the problem will appear when you try to send() through that socket again.
Code (integrity matters):
if(send(new_sockfd, "some words here...", 65535, 0) == -1){
perror("server: send");
}
I'm making this simple example from server to client where the server functions as a echo server! So the client gets input from the user and sends it to the server, the server then sends it back.
I just got stuck on the input from the user. I used stuff like getchar, scanf and fgets. But when I start typing and press ENTER, then it should continue to the next thing in the program... Sadly that ain't happening.
Here is my code for the message part:
while(1)
{
char message[1000], servermessage[1000];
printf("You: ");
scanf("%s", message);
printf("%s\n", message);
if (send(sock, message, strlen(message), 0) < 0)
{
printf("sending failed\n");
return (EXIT_FAILURE);
}
int received = recv(sock, servermessage, sizeof(servermessage), 0);
if (received < 0)
{
printf("received failed\n");
return (EXIT_FAILURE);
}
servermessage[received] = '\0';
printf("Server: %s\n", servermessage);
}
close(sock);
After you type the first time, you call recv(), it will block until there is some data to read, you client didn't read any data, so nothing happen. You need check your echo server to find what's wrong. If you need a echo server to test your client, you can use the code for server here.
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.
Re: this client<->server (foodrequest-foodinfo scenario) I am trying to send receive to a successful client-server connection sock_fd. In this loop, I receive the first information back but the next iteration stops at the keyboard input ie readInFood(). Is there anything wrong with the way I am handling the buffer? or otherwise.
RESPONSE_BUFFER = 2200;
INPUT_BUFFER = 100;
int numbytes;
char foodType[INPUT_BUFFER];
char foodResponse[RESPONSE_BUFFER];
do {
//send a message to server
if (send(sock_fd, readInFood(foodType), INPUT_BUFFER, 0) == -1)
perror("send");
//receive the message
if ((numbytes = read(sock_fd, foodResponse, RESPONSE_BUFFER)) == -1) {
perror("receive");
exit(EXIT_FAILURE);
}
//end the buffer string
foodResponse[numbytes] = '\0';
//print the buffer
printf("\nThis is the information you require: %s", foodResponse);
} while (foodType[0] != 'q' || foodType[0] != 'Q');
My guess is that your socket is blocking because it expects more information or its not getting anything else. In that case perror() will not fire, but your program will continue to wait for info.
I basically have a server set up and I'm accepting new clients(UNIX) and i'm using select() command to wait for activity on file descriptor but I'm not sure how to write from the clients side and then read it on the servers side
FD_ZERO(&readfds);
FD_SET(server_sockfd, &readfds);
FD_SET(STDIN_FILENO, &readfds);
while (1) {
testfds = readfds;
select(4 + MAXCLIENTS, &testfds, NULL, NULL, NULL);
for (fd = 0; fd < 4 + MAX_CLIENTS; fd++) {
if (FD_ISSET(fd, &testfds)) {
if (fd == server_sockfd) { /* new connection request */
client_sockfd = accept(server_sockfd, NULL, NULL);
if (num_clients < MAXCLIENTS) {
FD_SET(client_sockfd, &readfds);
num_clients++;
} else {
sprintf(message, "XSorry, too many clients. Try again later.\n");
write(client_sockfd, message, strlen(message));
close(client_sockfd);
}
} else if (fd == STDIN_FILENO) {
fgets(kb_message, BUFSIZ + 1, stdin);
if (strcmp(kb_message, "quit\n") == 0) {
sprintf(message, "XServer is shutting down.\n");
for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++) {
if (FD_ISSET(fd2, &readfds)) {
write(fd2, message, strlen(message));
close(fd2);
}
}
close(server_sockfd);
exit(EXIT_SUCCESS);
} else {
sprintf(message, "M%s", kb_message);
for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++)
if (FD_ISSET(fd2, &readfds))
write(fd2, message, strlen(message));
}
} else { /* client leaving */
close(fd);
FD_CLR(fd, &readfds);
num_clients--;
}
}
}
}
How would I handle write request from clients and then write back to them, would it be under "else" and how can I check if client is exiting or writing.
Thanks
The most common mistake with select(2) is not re-initializing the descriptor sets, since second, third, and forth arguments are input-output parameters.
Setup an fd_set, for reading before the outer loop, add listening socket descriptor to it, enter the loop, make a copy of the this fd_set and give the copy to select(2). When new connection arrives, add its descriptor to the original fd_set. Same for closed socket (error or EOF on read(2)) - remove the descriptor from the original fd_set.
Hope this helps.
You are correct in thinking you need the read code in your 'else' block. If a file descriptor triggers and it isn't stdin or the 'connect' descriptor, then it is one of your clients attempting to send you data. When one of those file descriptors is triggered in the select, you need to call 'read' on that descriptor to read the data into the buffer. The read command will return you the number of bytes read. If this is a positive number, then it indicates the client has sent you data. If it is zero, then that indicates that the client has ended the TCP connection to your server.
The else block will look something like:
else
{
//Existing connection has data for us to read
if((nBytes = read(fd, buffer, MAXBUFFER)) <= 0)
{
if(nBytes == 0)
{
//Actually, its sending us zero bytes, connection closed
printf("Socket %d hung up\n", fd;
}
else
printf ("Read Error"\n)
}
Also, Follow Nikolai N Fetissov's advice above and make sure that when client's connect you store their fd in a permanent fd_set structure, as the one you are using is being modified by the select call.
Your problem might be that you have a variable called read. It's going to mask one of hte functions you need to use - the read() system call to get data out of the socket. The client puts it in with write(). You might also want to check the return value from select(), which will tell you how many of the file descriptors are ready for reading. Then you can check which ones using FD_ISSET(). It looks like you're doing that part already (except you seem to be checking the wrong variable?)... just call read() on that file descriptor to get out the data the client wrote.
else
{
bzero(buf,100);
n=read(i,buf,100); // Read the client message
buf[n]='\0';
if(n==0) // Check the client is closed or not
{
printf("%d is closed\n",i);
close(i);
FD_CLR(i, &master);
if(i==fdmax)
fdmax--;
}
else
{
n=strlen(buf);
write(1,buf,n);
fflush(stdout);
write(1,"Enter the message\n",18);
bzero(buf,100);
read(0,buf,100);
buf[n]='\0';
write(i,buf,n);
fflush(stdout);
}
}
Notes:
After accept the client, Add the client in the fd set.
Then read the message from the client
If the message is equal to 0, then the client is closed.
If you want to send the message to the client, using the client fd, you can send to the client