server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
char *result1 = "Ian G. Harris";
char *result2 = "Joe Smith";
char *result3 = "Jane Smith";
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
error("ERROR on accept");
}
while (strcmp(buffer, "+++") != 0)
{
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Address server started\n");
if (strcmp(buffer, "harris#ics.uci.edu\n") == 0)
{
printf("%s\n", result1);
}
else if(strcmp(buffer, "joe#cnn.com\n") == 0)
{
printf("%s\n", result2);
}
else if(strcmp(buffer, "jane#slashdot.org\n")==0)
{
printf("%s\n", result3);
}
}
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3)
{
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
while (strcmp(buffer, "+++") != 0)
{
printf("> ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
}
return 0;
}
I am new to c and I am writing a server.c and client.c. The problem of my code is that I cannot make the program keep taking inputs until I enter "+++" to quit. The correct output is shown below:
client terminal:
> harris#ics.uci.edu
Ian G. Harris
> joe#cnn.com
Joe
>
server terminal:
Address server started
harris#ics.uci.edu
joe#cnn.com
in my code, when I enter "harris#ics.uci.edu" in client terminal, it does the following:
> harris#ics.uci.edu
(empty line)
and it does not take any input anymore.
Is there something wrong in the while loop? can someone help me to fix it? Thanks in advance.
Few things:
In the client loop, you do a write and a read on the socket. But your server never writes to that socket(no write call in the server, only read). As a result, your client gets blocked on the read call. That's why you cannot enter more...
In general, you need to check how much you wrote in and keep writing until done (a loop is needed).
int n = 0;
while (n != strlen(buffer){
n += write(sockfd,&buffer[n],strlen(buffer)-n);
}
Same goes for reading from a socket:
int n = 0;
while (n != strlen(buffer){
n += read(sockfd,&buffer[n],strlen(buffer)-n);
}
Here's what I believe is likely happening.
Client sends some chunk of data. Possibly all of the string harris#ics.uci.edu, but possibly less.
The server reads some chunk of this, most likely less than the full string, say harris#ic.
The server performs the strcmp, which doesn't match anything, so returns to the top of the loop.
The server reads the remainder of the email, say s.uci.edu into buffer, thus overwriting it.
Again, this doesn't match anything, so the server goes to the top of the while loop again.
The server hangs on the read call, waiting for data from the client. Because the client is waiting for a reply, it's stuck on its own read call. ...And nothing else happens.
There are two main problems here. First, TCP sockets are just streams of bytes, and when you read data from them, the OS no longer keeps it around. You are now expected to handle any previously- or partially-read data if you need. And second, the OS often transmits (both sending and receiving) fewer bytes than you request. While you ask that the full string harris#ics.uci.edu be sent, only a portion of that may be sent, or only a portion of that may be read on the other side.
This means two things for you. It's always important to check the amount of data read/written any time you call read(2) or write(2), but it's crucial in networking. Make sure you read/write as much as you need (the full email in this case) before moving on to, for example, waiting for a reply.
The second thing is that you need some way of delineating full messages and buffering partial messages. In what you've got, as is common in lots of text-based messaging protocols, the newline \n is your delimiter. So instead of a single call to read(2) in the server, you need something like this (pseduocode):
while newline not in data:
data += read(sockfd, ...)
Once you receive your newline, process the full message, but don't throw away any extra bytes you've read from the next message. Keep those around, and append the next bytes read from the socket to them, and so on.
EDIT:
Note that it's usually better to use recv(2) and send(2) when working with sockets. The read(2)/write(2) system calls will work just fine, but the others are more clear when working with sockets, and allow you to specify other flags, for example, peeking at the bytes currently on the socket or waiting until all the bytes you request are available before returning.
Related
I am trying to write a server that can handle at most 5 concurrent clients.
Whenever a client gets successfully connected to the server & the number of clients is less than or equal to 5, the server sends a welcome message, generates a 5 digit unique random number for identifying that client, sends this number to the client and prints this number in the console.If the number of clients tends to be greater than 5, then for each new request, it just sends a message "Connection Limit Exceeded" to the client & closes the connection.
Client just prints the messages sent by the server.
The problem I'm facing is that, the random number is not being propagated properly to the client.Few times the client prints the same number as generated by the server but few times the client just prints 0(as the variable storing incoming value of that random number is initialized to 0).
What could be the reason behind this?
Here are the codes for client and server:
server:
/* A simple server in the internet domain using TCP
The port number is passed as an argument
This version runs forever, forking off a separate
process for each connection
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <stdlib.h>
void dostuff(int); /* function prototype */
void write_once (int sock);
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, pid, count = 0;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
count++;
if (pid < 0)
error("ERROR on fork");
if (pid == 0 && count <=5 ) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
if (pid == 0 && count >= 5 ) {
close(sockfd);
write_once(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
/******** DOSTUFF() *********************
There is a separate instance of this function
for each connection. It handles all communication
once a connnection has been established.
*****************************************/
void dostuff (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = write(sock,"Welcome\n",8);
if (n < 0) error("ERROR writing to socket");
srand((unsigned int)time(NULL));
int r = rand() % 90000 + 10000;
int converted_r = htonl(r);
n = write(sock, &converted_r, sizeof(converted_r));
if (n < 0) error("ERROR writing to socket");
printf("%d\n", r);
}
void write_once (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = write(sock,"Connection Limit Exceeded!!",28);
if (n < 0) error("ERROR writing to socket");
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
int received_int = 0;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
n = read(sockfd, &received_int, sizeof(received_int));
if (n < 0)
error("ERROR reading from socket");
printf("%d\n", ntohl(received_int));
close(sockfd);
return 0;
}
Reference
The issue is that TCP is a stream oriented protocol, and not packet oriented. So it may happen that
The first read() of the client reads what the first write() of the server sent ("Welcome")
The second read() of the client reads what the second write() of the server sent (Your number)
This is what you expect and what sometimes happens.
However, it might also be that the client reads the data of both writes of the server at once! This usually happens when
either the server aggregated the two writes to a single tcp-packet
or the client reads the data after both tcp segments with data arrived
You cannot make sure what happens and cannot rely on any specific behaviour.
How to fix this depends solely on your protocol. If the first message is always "Welcome\n", then try to read only 8 bytes first. If you happen to read n < 8 bytes, you have to retry and read 8-n bytes to get the rest of the message. Subsequently read sizeof(received_int) bytes, also watching for the real number of bytes received.
If the message is of variable length you will have to use some kind of framing like a preceding length-byte or something like that.
Hi I was reading about non-blocking calls using select() from Beej's guide, but I'm still confused as to how to change my simple client-server code to one that is non blocking. Could anyone tell me what changes do I need to make in the server code as well as the client code for that?
Here's the server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
Here is the client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
close(sockfd);
return 0;
}
The way select(2) makes things non-blocking is by waiting for I/O to become possible without blocking (e.g., when new data is available). When using select(), you wouldn't normally have to put the monitored descriptors into non-blocking mode (with e.g. SOCK_NONBLOCK), so in a sense select() is specifically about avoiding having to use non-blocking I/O.
select() is used to wait for events on multiple descriptors at once. An event here is something that would make it possible to read(2) from or (depending on how you use select()) write(2) to the descriptor without blocking.
As an example, you could use select() to simultaneously wait for new client connections and data from already connected clients in your server (assuming you extend it to handle multiple clients). To do this, you would use select() to monitor both sockfd and any descriptors you get back from accept(2). Without select(), you would have to use some form of non-blocking I/O (or separate threads) instead to avoid getting stuck in e.g. the accept() until a new client connects, which would prevent you from seeing data from other clients in the meantime. That would be both messier to implement and also less efficient than sleeping in a single location.
select() doesn't do any I/O by itself. It only notifies you when I/O becomes possible without blocking. You pass it a set of descriptors, and it tells you whenever I/O becomes possible on any of them. (And also tells you which descriptors it's possible on.)
In addition to waiting for data on sockets, you could use select() to wait for e.g. user input on stdin at the same time. There are many different types of descriptors that can be select()ed on.
I am trying to make a protocol (built ontop of TCP) that can send strings from the client to the server on port 457. Here is what I have so far:
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"U got your messaze",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
close(sockfd);
return 0;
}
I feel as though I am not setting up the protocol properly. Am I?
You should write a specification for your protocol first. Then, after reviewing it, you implement the specification. You are basically asking us to reverse engineer your protocol. This is a backwards approach to creating a protocol. You should already have a clear intent of what your program needs to do before you begin implementing it.
Your server program acts as a limited kind of ECHO server, in that no more than 255 bytes of input from the client is accepted. Whatever the server was able to read is logged to the console, and the message U got your messaze is sent to the client as a response.
Some issues you may want to address:
Although unlikely, it is possible that your read() call returns with less data than what the client sent, even if the client sends less than 256 bytes. For example, if the client sends aaaaaaaaaa one byte at a time, your server might only see the first a, and assume it is a complete message.
You don't take precautions against writing to an already closed connection. This may generate SIGPIPE, and cause your program to exit unexpectedly.
Signals generally may interrupt your system calls. You should detect this condition and restart your system calls if that occurs.
You have some incorrect types:
htons expects uint16_t as parameter
htons((uint16_t)portno);
read() and write() expects ssize_t
ssize_t n;
bzero is deprecated, use
memset(buffer, 0, sizeof(buffer));
bcopy is deprecated, use
memmove(server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length);
NUL terminate buffer when read() is used
/* bzero(buffer,256); Not needed */
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
buffer[n]= '\0'; /* here */
printf("Here is the message: %s\n",buffer);
And note that modern programs uses send() and recv() instead of read() and write()
Finally, don't use magic numbers
fgets(buffer, 255, stdin);
instead:
fgets(buffer, sizeof(buffer), stdin); /* 256 */
And why 255? the fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, so 256 is correct.
I am working on a implementing a multithread multi client single server socket in C. However for whatever reason currently the program, when using pthread_create() to create a new thread, it does not advance past that line of code. I have put print lines before and after this line of code and all of the print lines before hand print fine but none of them after print. This leads me to believe that pthread_create() is somehow buggy. The strange thing about this is I can have 1 client connect and successfully sent/receive data from the server but because the loop that the listen() command is in is not advancing I cannot take on additional clients. I appreciate your help in this matter.
Server Code
#include <stdio.h>
#include <stdlib.h> //for IOs
#include <string.h>
#include <unistd.h>
#include <sys/types.h> //for system calls
#include <sys/socket.h> //for sockets
#include <netinet/in.h> //for internet
#include <pthread.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
void *threadFunc(int mySockFd)
{
int n;
char buffer[256];
do
{
bzero(buffer,256);
n = read(mySockFd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
else if(strcmp(buffer, "EXIT\n") == 0)
{
printf("Exit by user\n");
pthread_exit(NULL);
}
else
{
printf("Here is the message: %s\n",buffer);
n = write(mySockFd,"I got your message",18);
if (n < 0)
{
error("ERROR writing to socket");
}
}
}while(n >= 0);
}
int main(int argc, char *argv[])
{
int sockfd;
int newsockfd;
int portno;
pthread_t pth;
int n; /*n is the return value for the read() and write() calls; i.e. it contains the number of characters read or written.*/
int i = 0;
printf("after var decl");
socklen_t clilen; /*clilen stores the size of the address of the client. This is needed for the accept system call.*/
char buffer[256]; /*The server reads characters from the socket connection into this buffer.*/
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
error("ERROR on binding");
}
do
{
printf("before listen");
listen(sockfd,5);
printf("after listen");
clilen = sizeof(cli_addr);
printf("before accept");
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
printf("after accept");
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
printf("after pthread create");
if (newsockfd < 0)
{
error("ERROR on accept");
}
}while(1 == 1);
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
printf("Here is the message: %s\n",buffer);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
and here is the Client Code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /*The file netdb.h defines the structure hostent, which will be used below.*/
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd;
int portno;
int n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3)
{
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
error("ERROR connecting");
}
do
{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if(strcmp(buffer,"EXIT\n") == 0)
{
printf("Connection Terminated\n");
break;
}
if (n < 0)
{
error("ERROR writing to socket");
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
printf("%s\n",buffer);
if (n < 0)
{
error("ERROR reading from socket");
printf("%s\n",buffer);
}
}while(1 == 1);
close(sockfd);
return 0;
}
Two errors:
You are casting too much, the only place here should be the inaddr stuff.
You are not listening to your compiler, crank up the warning level.
Now, the problem (or maybe just one?) is actually this:
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
This will call threadFunc(newsockfd) and pass the result to pthread_create. The second part will never happen though, because that function calls pthread_exit or falls off the end without returning anything, which could cause anything to happen.
Your server code isn't displaying the printf statements reliably is because you didn't end the strings passed to printf with a "\n".
Change all of your printf statements to include a trailing \n such that output will be "flushed" immediately. E.g.
Instead of:
printf("after pthread create");
Do this:
printf("after pthread create\n");
Repeat that fix for all of your printf statements. And then the program flow will be more readily visible as clients connect to it.
There's probably about 5 or 6 other bugs in your code. The main one that I want to call out is just because the client sent 4 bytes of "EXIT", doesn't mean the TCP stream won't fragment that into "EX" and "IT" across two seperate read calls depending on the state of the intertubes. Always write your protocol code as if read/recv were only going to return one char at a time. OR just use MSG_WAITALL with recv() so that you always read the chunk size.
Hello i am trying to make a TCP client/server that i want these things.
The client will give the filename or the path of filename of a file.
The server will find that file and give these details:
permissions,size,owner,group of owner,date modified/created,number of words,id and priority of user and send these to client of -1 if something goes wrong.The client will print that details.I have done a lot of this things but i have a huge problem so i cant continue,my problem is that server cant recognize path of file but i tried with naming the file and communication its OK.What i am doing wrong?
Thank you in advance
CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[1024];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the filename or path of filename: ");
bzero(buffer,1024);
fgets(buffer,1024,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,1024);
n = read(sockfd,buffer,1024);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return 0;
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/resource.h>
#include <sys/time.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
FILE *fp;
int sockfd, newsockfd, portno, clilen,i;
char buffer[1024],filename[1024];
char * pPath;
struct sockaddr_in serv_addr, cli_addr;
int n;
int which = PRIO_PROCESS;
id_t pid;
int ret;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,1024);
n = read(newsockfd,buffer,1024);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
system("ls -al 1.txt > ls.txt");
system("wc -w 1.txt > wc.txt");
/* pPath = getenv ("PATH");
if (pPath!=NULL)
printf ("The current path is: %s\n",pPath);
system("touch path.txt");
fp=fopen("path.txt","w");
if (fp==NULL) exit(1);
fprintf(fp,pPath);
fclose(fp); */
pid = getpid();
ret = getpriority(which, pid);
printf("priority %d user id %d ret %d",which,pid,ret);
system("paste ls.txt wc.txt user.txt > info.txt");
fp=fopen("info.txt","r");
if (fp==NULL) exit(1);
for(int i=0;i<1000;i++){
fscanf(fp,"%c",&buffer[i]);
}
fclose(fp);
n = write(newsockfd,buffer,1024);
if (n < 0) error("ERROR writing to socket");
return 0;
}
}`
Thank you for the fast reply.To be specific,professor didn't ask us to make this txt files i created but i created cause i couldn't find a solution and i couldn't write everything to buffer.It should be like this:
buffer i coming with path from client
find path-file from buffer(this is where i have problem)
ls -al write to buffer(i wrote it to .txt)
wc write to buffer(i wrote it to .txt)
path write to buffer(haven't done this yet)
user info write to buffer(haven't done this yet)
buffer send to client
client prints buffer with all these info
I tried sprintf but i didn't understand exactly how you use it,but this commands looks better than mine thanks:).No is passed through buffer if i understand well.
You're probably going to need to pass the path into your system calls. Allocate a buffer (keep in mind that you should be doing checks on your buffers for security, but I understand this is probably homework) and use sprintf (http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/):
char lsbuf[1024];
sprintf(lsbuf,"ls -al %s > ls.txt",buffer);
system(lsbuf);
The proper way to do things (and the way your instructor most likely intends you to do them) would be to do the work of ls, wc, etc within the code. Calling system like this leaves you open to a whole new class of security holes.
Does the path passed to the server contain a trailing '\n'? If so you should remove it (for example by placing \0 character)
In your current code, nothing is really done with the input by the clients, and the behaviour does not match your description of it.
What is this supposed to do?:
for(int i=0;i<1000;i++){
fscanf(fp,"%c",&buffer[i]);
}
fclose(fp);
This will look for each character in the input (seeing as you use 1000 here, and the buffer can be 1024 characters, you are missing the last 24 characters) and return how many times it occurs in "info.txt". Note that you will also do a search for the NUL character ('\0'). Besides these carelessnesses it doesn't really do anything.
I assume you just want to find the string in the file, and work with the line number? You need a different method of searching strings. There are some clever and less clever algorithms for that. One of the more 'brute' algorithms is:
Search for the first character
Keep some flag as 'true' as long as all next characters match the expected character
If some character violates the match, go to the next search of the first character
Note that there are more efficient algorithms than this.
I did not scrutinize your network setup, assuming it works. It would be a good idea to either split the code up into several paragraphs using some more whitespace, or put the network setup into a different function.
First, use of bzero should be avoided since that function is deprecated. Use memset instead.
The function fgets, reads until a newline or the End-of-File is reached. Since a newline is a valid character, it is added to the string and a null character is appended.
If you type in "mytext" and then enter, the buffer will have "mytext\n\0".
Based on the current code, you are not even using the buffer from the client so it obvious it isn't working (not that it will due to the fgets() behavior due to an appended newline).
Sorry for replying like this but i didn't have an account,i am new to this(i didn't have problem with my projects for 4 years:P).I insert
char lsbuf[1024];
sprintf(lsbuf,"ls -al %s > ls.txt",buffer);
system(lsbuf);
and is working like a charm almost...It accepts the path and do ls but doesn't save the ls to ls.txt(creates empty file) and doesn't send it to buffer.Also i tried replaced memset and is working!!