I am learning the Sockets networking API. In this process, I have written a simple Echo server that uses TCP. I wrote the code in such a way that, as long as the server is running, anything typed on the client's console should be echoed back to it. However, I am unable to achieve this. Although, for the first input, I get the echo, from next time onwards, I do not get any message.
I know, we can implement it to run for many clients using fork(), but I want to know the reason behind the blocking of the client, and if possible ways to correct it.
Here is the code for the client:
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd;
char msg[MAXCOUNT];
char blanmsg[MAXCOUNT];
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
sfd = socket(AF_INET,SOCK_STREAM,0);
saddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr);
saddr.sin_port = htons(5004);
connect(sfd,(struct sockaddr*) &saddr, sizeof(saddr));
for(; ;) {
memset(msg,0,MAXCOUNT);
memset(blanmsg,0,MAXCOUNT);
fgets(msg,MAXCOUNT,stdin);
send(sfd,msg,strlen(msg),0);
recv(sfd,blanmsg,sizeof(blanmsg),0);
printf("%s",blanmsg);
fflush(stdout);
}
exit(0);
}
Here is the code for the server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,nsfd,n,i,cn;
char buf[MAXCOUNT];
socklen_t caddrlen;
struct sockaddr_in caddr,saddr; //Structs for Client and server Address in the Internet
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure
saddr.sin_family = AF_INET; //Internet Address Family
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5004);
bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
listen(sfd,1);
for(; ;) {
caddrlen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
cn = recv(nsfd,buf,sizeof(buf),0);
if(cn == 0) {
exit(0);
}
buf[cn] = '\0';
send(nsfd,buf,strlen(buf),0);
}
close(nsfd);
exit(0);
}
You shouldn't call accept within the loop on the server. Move the accept before the for loop on the server and it should work how you expect.
Calling accept in the loop like that will make the server block until a new connection comes in. Your client is only opening a single connection, so the server will block on the second call to accept.
Your code is doing precisely what you asked it to do. You told it to accept a connection, receive some data from that connection, send that data back to the connection, then accept another connection. That's what it's doing. I suspect you want to move the accept call outside the for loop.
I think you required a code which servers multiple clients as well as echo message to respective clients.
so just have a look to your code again and note down modification
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,nsfd,n,i,cn;
char buf[MAXCOUNT];
socklen_t caddrlen;
struct sockaddr_in caddr,saddr;
//Structs for Client and server Address in the Internet
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure
saddr.sin_family = AF_INET; //Internet Address Family
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5004);
bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
listen(sfd,5);/*request queue size*/
while(1)
{//main loop for cuncorent server
caddrlen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
if(fork()==0)
{//only child code for serving a particular client
for(; ;) {//loop for reading and writing back msg cotineously
cn = recv(nsfd,buf,sizeof(buf),0);
if(cn == 0) {
exit(0);
}
buf[cn] = '\0';
send(nsfd,buf,strlen(buf),0);
}//serving loop ends
close(nsfd);
exit(0);
}//child code ends
}//main while loop ends
exit(0);
}
Related
This is a test program. The client must send a text first and then the server replies. When client receive the "yellow" text from the server, the client receives and prints it just fine but when the server sends "red" after that, the printed message on client is "redlow". Why is this happening? is recvline[MAXLINE] combining the two together?
tcpclient.c
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAXLINE 20000
int main()
{
int sockfd;
int ret;
char recvline[MAXLINE];
char sendline[MAXLINE];
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(49152);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
ret = connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
if(ret == 0)
{
for(;;)
{
write(1,"\nsftc>",6);
if(fgets(sendline,MAXLINE,stdin)==NULL)
{
return 0;
}
send(sockfd, sendline, strlen(sendline),0);
if(recv(sockfd, recvline,MAXLINE,0)==0)
{
close(sockfd);
break;
}
else
{
printf("%s\n",recvline);
}
}
}
else
{
perror("connect error\n");
}
return 0;
}
tcpserver.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAXLINE 20000
//to create listen fd and bind
int createListenFD(struct sockaddr_in* servaddr)
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(servaddr, sizeof(*servaddr));
servaddr->sin_family = AF_INET;
servaddr->sin_addr.s_addr = htonl(INADDR_ANY);
servaddr->sin_port = htons(49152);
bind(listenfd,(struct sockaddr*)servaddr,sizeof(*servaddr));
return listenfd;
}
void* child_server(void* args)
{
printf("inside child\n");
char recvline[MAXLINE];
char sendline[MAXLINE];
int connfd = *((int*)args);
char* reply = "yellow";
int i = 0;
while(i<3)
{
recv(connfd, recvline, MAXLINE, 0);
send(connfd,reply,strlen(reply),0);
reply = "red";
i++;
}
return (NULL);
}
int main()
{
int* connfd;
struct sockaddr_in cliaddr, servaddr;
socklen_t clilen;
int listenfd = createListenFD(&servaddr);
listen(listenfd, 5);
pthread_t tid;
clilen = sizeof (cliaddr);
connfd = malloc(sizeof(int));
*connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen);
pthread_create(&tid, NULL, child_server,(void*)connfd);
pthread_join(tid, NULL);
close(listenfd);
}
recv() stores only bytes that were actually received into the receiving buffer. In particular, it does not add a string terminator after the bytes it actually receives. If you want to interpret the data as a C string, then it is your responsibility to either
add one, or
ensure that the server sends one, and that the client doesn't consider the transmission complete until it receives that.
So,
is recvline[MAXLINE] combining the two together?
Effectively, yes. The characters 'y', 'e', 'l', 'l', 'o', 'w' are recorded in that array by the first recv() call. You are lucking out (or maybe unlucking out) that the next byte happens to be a null character, so that when you print the contents of recvline, you get exactly "yellow". The second recv() call overwrites the first three bytes of the buffer with the characters 'r', 'e', 'd', but again, it does not write a string terminator. It follows that if you then print recvline, you get "redlow".
It is important to consider the recv() function's return value. It informs you about several things that you really need to know:
on a successful reception of one or more bytes, it tells you exactly how many bytes were received. (You can use this in your program to know where to put a string terminator.)
on an error, including a fairly benign one such as the function being interrupted by a signal before transferring any bytes, it notifies you that an error in fact occurred (by being the value -1; and errno then tells you what kind of error).
when no more data are available as a result of the remote end having closed the connection, it notifies you of this (by being 0).
It is also important to understand that on a stream-oriented socket such as one based on TCP, send() and recv() are not message-oriented. It is not safe to assume that each send() on one side pairs perfectly with one recv() on the other. Data sent by one send() may be split across more than one recv(), and data sent by multiple send()s may be received by a single recv().
Nor is it in general safe to assume that a send() or recv() will transfer the full number of bytes requested. Both partial sends and partial receives are possible.
I made a TCP Client/Server and I can run it one time. But when I try to run it more than one time, it gives me the following error: "Connection refused". Here's my code.
Client
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int net_socket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in net_addr;
net_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
net_addr.sin_family = AF_INET;
net_addr.sin_port = htons(3250);
int connection_state = connect(net_socket, (struct sockaddr*)&net_addr, sizeof(net_addr));
if (connection_state == 0) {
printf("Connected with the server.\n");
}
else {
printf("Connection with the server failed. [%s]\n", strerror(errno));
}
char net_message[256];
recv(net_socket, net_message, sizeof(net_message), 0);
close(net_socket);
shutdown(net_socket, SHUT_RDWR);
return 0;
}
Server
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int net_socket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in net_addr;
net_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
net_addr.sin_family = AF_INET;
net_addr.sin_port = htons(3250);
bind(net_socket, (struct sockaddr*)&net_addr, sizeof(net_addr));
listen(net_socket, 1);
struct sockaddr_in cl_addr;
int cl_size = sizeof(cl_addr);
int cl_socket = accept(net_socket, (struct sockaddr*)&cl_addr, (socklen_t*)&cl_size);
int loop = 1;
char net_message[256];
send(cl_socket, net_message, sizeof(net_message), 0);
close(net_socket);
close(cl_socket);
shutdown(net_socket, SHUT_RDWR);
shutdown(cl_socket, SHUT_RDWR);
return 0;
}
I've been trying to solve the problem by many ways but I'm a newbie. Thanks for the help in advance!
The problem is with your server lacking the SO_REUSEADDR socket option which leads to the bind() syscall failing. The reason is, that after a client disconnects from the server, the connection is still known by the system in TIME_WAIT state, to wait for late packets. These lead to the bind() to fail with EADDRINUSE if the above mentioned socket option is not set.
Use the following:
...
int one = 1;
setsockopt(net_socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
bind(net_socket, (struct sockaddr*)&net_addr, sizeof(net_addr));
...
and do error checks for all syscalls! That would have shown you the problem much earlier and had saved you much time.
Some more issues:
You are sending an uninitialized buffer net_message
A shutdown on a listen socket isn't sensible at all, since no connection is established on it (this here: shutdown(net_socket, SHUT_RDWR);)
The shutdown on the client socket has - if at all - to be performed before the close(cl_socket);. But it is not necessary at all in that case.
I have the following code for client and server
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int socket_fd;
struct sockaddr_in dest;
struct hostent *hostptr;
struct { char head; u_long body; char tail; } msgbuf;
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
bzero((char *) &dest, sizeof(dest)); /* They say you must do this */
hostptr = gethostbyname(argv[1]);
dest.sin_family = (short) AF_INET;
bcopy(hostptr->h_addr, (char *)&dest.sin_addr,hostptr->h_length);
dest.sin_port = htons((u_short)0x3333);
msgbuf.head = '<';
msgbuf.body = htonl(getpid()); /* IMPORTANT! */
msgbuf.tail = '>';
sendto(socket_fd,&msgbuf,sizeof(msgbuf),0,(struct sockaddr *)&dest,
sizeof(dest));
return 0;
}
server:
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int socket_fd, cc, fsize;
struct sockaddr_in s_in, from;
struct { char head; u_long body; char tail;} msg;
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
bzero((char *) &s_in, sizeof(s_in)); /* They say you must do this */
s_in.sin_family = (short)AF_INET;
s_in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */
s_in.sin_port = htons((u_short)0x3333);
printsin( &s_in, "RECV_UDP", "Local socket is:");
fflush(stdout);
bind(socket_fd, (struct sockaddr *)&s_in, sizeof(s_in));
for(;;) {
fsize = sizeof(from);
cc = recvfrom(socket_fd,&msg,sizeof(msg),0,(struct sockaddr *)&from,&fsize);
//printsin( &from, "recv_udp: ", "Packet from:");
printf("Got data ::%c%ld%c\n",msg.head,(long) ntohl(msg.body),msg.tail);
fflush(stdout);
}
return 0;
}
I'm looking for a way to change this code so that:
1.The client will send my name to the server and then will receive the server response.
2.On the server side, the server will receive the client name (instead of the current msg structure) and will send back its name.
I'm assuming I should just put my name in the msgbuf.body like this
msgbuf.head = '<';
msgbuf.body = 'liana';
msgbuf.tail = '>';
and delete the
msgbuf.body = htonl(getpid()); line.
or maybe make a new string for my name like this string name="liana";
and put it in the msgbuf.body like this msgbuf.body=name;(???)
is this the right deriction?
for reciving the response of the server I assume it is the same way as it was done for the server
should I add to client something like this?
int socket_fd, cc, fsize; // the socket that we receive to
struct sockaddr_in s_in, from; // decleration of the server and sending
(to the server) struct
fflush(stdout);//to ensure that whatever you just wrote to a file/the console is indeed written out on disk/the console.
bind(socket_fd, (struct sockaddr *)&s_in, sizeof(s_in));// conecting
between
the socket and all the details we entered
for(;;) {//infinite loop
fsize = sizeof(from);//set the size of the socket we resive to
cc = recvfrom(socket_fd,&msg,sizeof(msg),0,(struct sockaddr
*)&from,&fsize);//recive massage using UDP protocol
printf("Got data ::%c%ld%c\n",msg.head,(long) ntohl(msg.body),msg.tail);
//print the whole massage
fflush(stdout);//to ensure that whatever you just wrote to a file/the
console is indeed written out on disk/the console.
}
and just leave it like this without changing anything?
**how can I make the server receive the my name (instead of the current msg
structure)and send it back?
should I send it back using the
sendto(socket_fd,&msgbuf,sizeof(msgbuf),0,(struct sockaddr *)&dest,
sizeof(dest));
line?
**if I cant use the structure anymore how should i change this line?****
any help whould be appreciated,I'm kind of new to C and never worked with the client/server model
I've been approaching network programming these days, and I wrote two simple routines to check if I got it right. So I built the server on the desktop and started it, then I built the client on the laptop and I ran it, and everything went as expected. When I tried to run them the second time and on, the server kept looping and the client after two seconds gave "Error connecting!". If I try again after fifteen minutes it works, but then I have to wait again. Where am I wrong? The computers are both connected to my LAN, 79.13.199.165 is the IP of my modem/router, which forwards every incoming connection on port 53124 to the desktop. This problem doesn't occur when running both server and client on the same PC.
server.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main () {
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(53124);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
memset(sa.sin_zero, '\0', sizeof(sa.sin_zero));
int mysocket = socket(PF_INET, SOCK_STREAM, 0);
bind(mysocket, (struct sockaddr*)&sa, sizeof(sa));
listen(mysocket, 5);
int inc;
struct sockaddr_in inc_addr;
socklen_t inc_addr_size = sizeof(inc_addr);
inc = accept(mysocket, (struct sockaddr*)&inc_addr, &inc_addr_size);
if (inc != -1) {
printf("accepting client\n");
}
send(inc, "ciao", sizeof("ciao"), 0);
close(inc);
return 0;
}
client.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main () {
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(53124);
sa.sin_addr.s_addr = inet_addr("79.13.199.165");
memset(sa.sin_zero, '\0', sizeof(sa.sin_zero));
int mysocket = socket(PF_INET, SOCK_STREAM, 0);
if (mysocket == -1) {
printf("Could not create socket!\n");
}
if (connect(mysocket, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
printf("Error connecting!\n");
}
char message[5];
memset(message, '\0', sizeof(message));
recv(mysocket, message, 5, 0);
printf("%s\n", message);
return 0;
}
When the server closes the socket, a couple of ACK packets get sent backwards and forwards across the connection. There's no way to tell if the last ACK gets delivered successfully, so the connection goes into the TIME_WAIT state for a bit. This basically gives the TCP stack time to wait for any lost packets and throw them away.
It's possible to ignore this and reuse the socket straight away by setting SO_REUSEADDR using setsockopt(). There is a small danger that subsequent connects might get data they weren't supposed to but it shouldn't be a problem for your little test application.
Edit
By the way, one reason why you were probably getting confused by this is that you don't do any error checking on socket() bind() or listen(). The bind() call would certainly return an error and set errno, EINVAL on Linux.
I am new to network programming, and have been learning this by writing small programs that make use of the Socket API. Currently, I am writing a simple echo server, that uses fork to create a copy of it, as soon as it gets a connect request, this adds up as in improvement over the previous Iterative server (here). However, after I start the server and fire up the client, and type a message on its console, it quits unexpectedly. Running the program under Gdb shows that SIGPIPE was delivered. But as far as I know as the socket is still valid, a SIGPIPE shouldn't have occured. Any kind of help involved is appreciated.
Here is the client code
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,i;
struct sockaddr_in saddr;
char buff[MAXCOUNT];
char mesg[MAXCOUNT];
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr);
saddr.sin_port = htons(5008);
connect(sfd,(struct sockaddr*) &saddr,sizeof(saddr));
fgets(buff,MAXCOUNT,stdin);
send(sfd,buff,strlen(buff),0);
if (recv(sfd,mesg,MAXCOUNT,0) == -1) {
perror("Nothing to read\n");
exit(1);
}
printf("%s\n",mesg);
exit(0);
}
Here is the server code
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,nsfd,cn;
pid_t c;
char buf[MAXCOUNT];
socklen_t clen;
struct sockaddr_in caddr,saddr;
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5008);
bind(sfd,(struct sockaddr*) &saddr,0);
listen(sfd,2);
for (; ;) {
clen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr, &clen);
if( (c = fork()) == 0) {
close(sfd);
memset(buf,0,sizeof(buf));
cn = recv(nsfd,buf,sizeof(buf),0);
if ( cn == 0) {
perror("Reading from the client socket failed\n PROGRAM CRASH :\n");
exit(1);
}
buf[cn] = '\0';
send(nsfd,buf,strlen(buf),0);
close(nsfd);
exit(0);
}
}
return 0;
}
send(sfd,buff,strlen(buff),0);
if (recv(sfd,mesg,MAXCOUNT,0) == -1) {
perror("Nothing to read\n");
exit(1);
}
printf("%s\n",mesg);
The %s format specifier is for C-style strings, not arbitrary data. And since you throw away the return value from recv, you have no way to know how many bytes you got.
Your client also doesn't shut down the socket gracefully or make sure it has received all the data the server may send. So it's possible that you're triggering an abnormal termination. The server closes the connection when it's done sending, so the client should keep trying to receive until it detects that the connection has closed.