Sending a file content to a server: Socket - c

My code reads from a file line by line and sends it to a server.
client.c
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
FILE* pFile;
char* line = NULL;
//char buffer[256];
char* buffer;
int len;
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
pFile = fopen ("myfile.txt","r");
if (pFile==NULL)
{
printf("Error reading temp file\n");
exit (1);
}
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");
//loop
while (!feof(pFile)) {
//printf("Please enter the message: ");
line = readLine(pFile, line);
len=strlen(line);
buffer= (char*) malloc((len+1)*sizeof(char));
bzero(buffer,len);
memcpy(buffer,line,len+1);
// fgets(buffer,len,pFile);
printf("%s\n", buffer);
n = write(sockfd,buffer,strlen(buffer)+1);
if (n < 0)
error("ERROR writing to socket");
free(buffer);
free(line);
}
buffer= (char*) malloc(2048*sizeof(char));
bzero(buffer,2048);
n = read(sockfd,buffer,2048);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
free(buffer);
fclose (pFile);
close(sockfd);
return 0;
}
And
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#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[2048];
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");
else
printf("Socket connected\n");
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");
printf("Data Receieved by client: \n");
bzero(buffer,2048);
n=read(newsockfd,buffer,2048);
if (n < 0) error("ERROR reading from socket");
printf("%s\n",buffer);
n = write(newsockfd,"Server received the message",18);
if (n < 0)
error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
The problem is that the server reveives a few lines and misses a few. Not able to figure out what is wrong. Can some one help?
Client Side
[gaurav1.k#DELL-BUILD03 Socket]$ gcc -Wall client.c -o client.exe
[gaurav1.k#DELL-BUILD03 Socket]$ ./client.exe localhost 8000
I am line number One,am I?
Here comes line number Two.
Will you welcome, Line number Three? And I am your Friend.
I am here, It is me - Line number Four.
Hello All, I am line number Five, am I? Yes I am.
It is over, because I am line number six.
Server received th
[gaurav1.k#DELL-BUILD03 Socket]$
Server Side:
[gaurav1.k#DELL-BUILD03 Socket]$ gcc -Wall server.c -o server.exe
[gaurav1.k#DELL-BUILD03 Socket]$ ./server.exe 8000
Socket connected
Data Receieved by client:
I am line number One,am I?
[gaurav1.k#DELL-BUILD03 Socket]$
The content of file to be read is:
I am line number One,am I?
Here comes line number Two.
Will you welcome, Line number Three? And I am your Friend.
I am here, It is me - Line number Four.
Hello All, I am line number Five, am I? Yes I am.
It is over, because I am line number six.

For a scenario like this you usually want to implement a kind of communication protocol.
Most importantly, the server needs to know how many bytes it has to read to receive the whole content. So usually, you transfer the message size as the first part of your message (header). Then the server knows how many bytes to receive after that to consume the actual payload data.

The problem is multiple write at the client side, but only one read at the server side. How?
For every line the client will write into the socket, that is multiple write(you are using write in a loop), but in server you are having one read, that is single read(no loop's, so it will read only the first line).
For first line, you are reading at server side. But for second line the client is writing, but your server have no read statement(first read is already executed). Due to this you wont receive the full message
A simple solution is write the whole file content at a time, not line by line and read it.
Try the below change also-
n = write(newsockfd,"Server received the message",50); // Increase the size

It looks like the problem is that you don't check the result of the read and write functions, which can fail in partial success states, indicating the number of bytes they've successfully transferred. In general, you need to wrap these functions in a loop that repeats until the entire buffer has been read/written.

On top of the failure to properly account for the returns from system calls, as described by other posters, there is:
bzero(buffer,2048);
n=read(newsockfd,buffer,2048)
..
printf("%s\n",buffer);
If the read() returns 2048 bytes, the printf can UB as it tries to find a non-existent null after the end of the buffer. Either allocate/clear 2049 of read 2047, and even that will only work well for transferring plain ASCII text files, (ie files with no embedded nulls).

Related

TCP IP socket communication in C. During the client exit, intimating server?

I am checking the communication between 2 entities (A and B) for their presence. A is a server and B is a client. When the server is up and running, it waits for connections and when B starts, it sends a message "Available" every one second. Now, the problem is, when I terminate the B program( ctrl+c or press the close button of the terminal), the server A does not recognise and still continues its operation. I would like for it to display message like "B is no more available" or "communicating partner is off". I understand TCP would be a best fit for the connection oriented communication. Please suggest me the changes to incorporate the display message on server A, when B is closed.
PS: amateur in socket programming
EDIT1: Managed to display the Message. However, since the server is designed to listen to many connections, I would like to make it accept the connections and not end the loop. Any guidance here would be useful.
SERVER(A) TCP SERVER
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
clilen = sizeof(cli_addr);
// bind the host address using bind() call
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
perror("ERROR on binding\n");
exit(1);
}
// start listening for the clients,
// here process will go in sleep mode and will wait for the incoming connection
listen(sockfd, 5);
// accept actual connection from the client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
// inside this while loop, implemented communication with read/write or send/recv function
//printf("start");
while (1) {
bzero(buffer,256);
n = read(newsockfd, buffer, 255);
if (n < 0){
perror("ERROR in reading from socket");
exit(1);
}
if (n == 0){
perror("Client has abruptly ended\n");
close(sockfd);
exit(1);
}
printf("client said: %s \n", buffer);
n = write(newsockfd, buffer, strlen(buffer));
if (n < 0){
perror("ERROR in writing to socket");
exit(1);
}
// escape this loop, if the client sends message "quit"
// if (!bcmp(buffer, "quit", 4))
// break;
}
return 0;
}
CLIENT(B) TCP CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server = gethostbyname("127.0.0.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);
// connect to server with server address which is set above (serv_addr)
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR while connecting");
exit(1);
}
// inside this while loop, implement communicating with read/write or send/recv function
while (1) {
strcpy(buffer,"Available");
n = write(sockfd,buffer,strlen(buffer));
if (n < 0){
perror("ERROR while writing to socket");
exit(1);
}
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if (n < 0){
perror("ERROR while reading from socket");
exit(1);
}
printf("server replied: %s \n", buffer);
// escape this loop, if the server sends message "quit"
//if (!bcmp(buffer, "quit", 4))
// break;
sleep(1);
}
return 0;
}
Please anybody tell me how to handle that issue?
When the client closes the TCP connection, the server's call to read(newsockfd) will return 0 to indicate that the connection has closed. At that point, the server should close(newsockfd), print your "Client has gone away message", and not use newsockfd anymore (i.e. either the server program should exit, or, more usefully, it should just break out of its while(1)-loop and go back to calling accept() again, so that the next time a client runs it too can connect to the server)

how to fix the while loop in server.c and client.c

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.

Unexpected output in IPC using sockets

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.

Am I creating the Protocol correctly?

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.

How you pass path from client to server?

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!!

Resources