How you pass path from client to server? - c

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

Related

Packet missing when both parties sending at the same time in a TCP connection

I am coding with a tcp connection. But I observed some packet loss when both side sending/receiving messages. I can't figure out what's wrong here.
Below is a minimum example. I use gcc(with no flag/option) to compile.
Each time in the for loop the two parties sends a 128 byte message to each other. Which contains a sequence num(the first byte). But it seems that some times the sent message are always missing.
Server:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <stdlib.h>
void error(const char *msg)
{
printf("%s\n",msg);
exit(0);
}
FILE* server_open_socket(int portno)
{
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
int on=1;
if((setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
{
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
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");
close(sockfd);
FILE *stream;
stream = fdopen(newsockfd, "wb+");
printf("connected Server at %d\n",portno);
return stream;
}
int main()
{
FILE *S;
S=server_open_socket(12345);
char sbuffer[128],rbuffer[128];
for(int i=0;i<128;i++)
sbuffer[i]=0;
for(int i=0;i<256;i++)
{
rbuffer[0]=0;
sbuffer[0]=1+i%255;
int a=fwrite(sbuffer,sizeof(unsigned char),128,S);
int b=fread(rbuffer,sizeof(unsigned char),128,S);
if((a!=128)||(b!=128))
printf("Network error!\n");
if(rbuffer[0]!=sbuffer[0])
{
printf("msgerror! %d %d\n",rbuffer[0],sbuffer[0]);
exit(0);
}
}
}
client:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <stdlib.h>
void error(const char *msg)
{
printf("%s\n",msg);
exit(0);
}
FILE* client_open_socket(int portno)
{
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname("localhost");//gethostbyname(argv[1]);
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);
while(connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1) {
sleep(1000);
}
FILE *stream;
stream = fdopen(sockfd, "wb+");
printf("connected Clinet at %d\n",portno);
return stream;
}
int main()
{
FILE *S;
S=client_open_socket(12345);
char sbuffer[128],rbuffer[128];
for(int i=0;i<128;i++)
sbuffer[i]=0;
for(int i=0;i<256;i++)
{
rbuffer[0]=0;
sbuffer[0]=1+i%255;
int a=fwrite(sbuffer,sizeof(unsigned char),128,S);
int b=fread(rbuffer,sizeof(unsigned char),128,S);
if((a!=128)||(b!=128))
printf("Network error!\n");
if(rbuffer[0]!=sbuffer[0])
{
printf("msgerror! %d %d\n",rbuffer[0],sbuffer[0]);
exit(0);
}
}
}
Here is a possible output:
server:
Network error!
msgerror! 0 3
client:
msgerror! 3 2
It seems that the message starting with "2" from the server is missing.
This issue seems to disappear if I let the two parties send message in order(server sends and then listens, client listens then sends). But I don't know why either.
When it comes to multiple parties, for example, three machines/hosts/parties, each of them has a distinct message for each other party: 6 messages in all. How should I handle such task?
You're totally confusing the stdio library.
You can't use a buffered stream in both directions on the same socket at the same time. The buffered stream mechanism is designed with a certain model in mind: that of an ordinary file on disk. The socket is not like that. That is, the library is designed for a model where the "write" side and the "read" side share a single underlying file pointer and you can both read and write into the same area of the data.
Think about how this would work if you were operating on an ordinary file on disk and contrast that with the socket. You fread 128 bytes from the "file". This causes the library to actually read (as in the read(2) system call) at least 128 bytes -- but it will try to read more than that normally, up to some large buffer size -- into its internal buffer. It will then transfer 128 bytes into your buffer, and set its internal file offset to 128. If you then write 128 bytes, the stdio library will, I believe, overwrite any bytes in its internal buffer starting at offset 128 for a length of 128.
If it had read more than 128 bytes initially, it would now need to reposition the underlying file pointer before it could actually flush that data "to disk" (i.e. call write(2)). I'm not sure exactly how much it would write then, but it will attempt to keep a coherent view of that data in its internal buffer -- but again it's assuming a model which is totally different than a bidirectional socket data stream. So, prior to doing the write, it will attempt to reposition the file pointer in preparation for updating the file and because the "file" is actually a socket, the lseek(2) system call fails (which explains the "network error" you're seeing).
You can create two separate buffered streams on the socket, one for reading (fdopen(sockfd, "rb")) and one for writing (fdopen(sockfd, "wb")). I don't know if that is guaranteed to work by the library standardization -- probably not -- but since each buffered stream is totally independent and since you're only reading from one and only writing to the other, there aren't any issues with the library needing to adjust its file offset in a way that affects both directions, and the library can treat each "stream" pretty much exactly as a file on disk that is slowly growing.
If you try that, you'll need to add some fflush(3) calls in order to force the library to actually send the buffered data to the peer. Because otherwise, it doesn't know it needs to do that.

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.

"no newline at end of file" C [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I'm using this command to compile:
gcc –Werror –std=c99 client.c –o client
CODE:
#include <string.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFFER_SIZE 1000
#define PORT_NUM 8888
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[BUFFER_SIZE];
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 (1)
{
bzero(buffer, BUFFER_SIZE);
fgets(buffer, BUFFER_SIZE, stdin);
if((strncmp(buffer,"close",5) == 0 ))
break;
printf("Please enter the message: ");
bzero(buffer, BUFFER_SIZE);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer, BUFFER_SIZE);
n = read(sockfd,buffer, BUFFER_SIZE-1);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
}
close(sockfd);
return 0;
}
Trying to compile it in a shell on VM whos OS is linux
This error is driving me crazy, I don't understand what to do inorder to fix this.
I thought the client.c file is damaged, so I copied and pasted into a new .c file. When that failed, I wrote it from 0 and still getting this error.
Thanks in advance!
Text processing programs don't always agree on whether a \n character is line separator or line terminator - the difference being whether or not the last line in a file should be followed by a \n character or not.
I've never seen GCC complain about this, but you didn't indicate where the error is actually coming from.
You should be able to correct the situation by simply pressing ENTER after the last line in your file.
Alternatively, you could open, and them save the file using an editor like Vim, which considers it a line terminator.
As a matter of comparison, most UNIX tools also consider \n a line terminator, and include it after the final line. This allows one to cat a file without corrupting whatever follows (e.g. another file, the shell prompt, etc.)
Add Enter (new line) behind the closing bracket.

Sending a file content to a server: Socket

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).

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.

Resources