I am working on a TCP based file transfer program running on Unix with sockets. I need to create a program that opens two separate data connections similar to the FTP protocol. One connection is used for client and server to send commands to each other and the other is used to actually transfer the bytes from the files. In other words, there is one client, one server, and two connections between them.
I am creating two socket connections on different ports – the hosts are the same. So for example the command connection would be 127.0.0.1:6000 and the IO connection would be 127:0.0.1:6005.
Server:
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("Can't create a socket");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(6005);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("Can't bind name to socket");
exit(1);
}
listen(socket_fd, 10);
while (TRUE)
{
client_len= sizeof(client);
if ((connect_fd = accept (socket_fd, (struct sockaddr *)&client, &client_len)) == -1)
{
fprintf(stderr, "Can't accept client\n");
exit(1);
}
printf(" Remote Address: %s\n", inet_ntoa(client.sin_addr));
temp = buffer;
num_bytes = BUFLEN;
while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
if(strncmp("SEND", buffer, 4) == 0)
{
printf("Client Sending Data...\n");
// setup server type socket for the file transfer data connection
struct sockaddr_in data_conn, data_client;
int conn_fd, new_conn_fd, data_client_len;
char *filename;
if((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot Create Data Connection Socket!\n");
exit(1);
}
// populate data connection socket
bzero((char *)&data_conn, sizeof(struct sockaddr_in));
data_conn.sin_family = AF_INET;
data_conn.sin_port = htons(6000);
data_conn.sin_addr.s_addr = htonl(INADDR_ANY);
// bind the new data connection socket
if (bind(conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
{
perror("Can't Bind Name to Data Connection Socket!\n");
exit(1);
}
listen(conn_fd, 5);
bzero(temp, BUFLEN);
bzero(buffer, BUFLEN);
temp = buffer;
num_bytes = BUFLEN;
while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
fprintf(stdout, "Receiving File: %s\n", buffer);
FILE *fp;
fp = fopen(buffer, "w");
if(fp == NULL)
{
perror("Could not open destination file\n");
exit(1);
}
data_client_len= sizeof(data_client);
if ((new_conn_fd = accept (conn_fd, (struct sockaddr *)&data_client, &data_client_len)) == -1)
{
fprintf(stderr, "Can't accept data connection client\n");
exit(1);
}
bzero(temp, BUFLEN);
bzero(buffer, BUFLEN);
temp = buffer;
num_bytes = BUFLEN;
printf("foo\n"); // this prints! so issue must be below
while ((n = recv (new_conn_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
// just printing the file contents for now
fprintf(stdout, "received file contents: %s\n", buffer);
fclose(fp);
}
else if(strncmp("GET", buffer, 3) == 0)
{
// get stuff not implemented yet
}
else
{
perror("Client Issued an Invalid Command\n");
exit(1);
}
close (connect_fd);
}
close(socket_fd);
return(0);
Client:
// first check to make sure that the FTP command was either GET or SET
if(strncmp("GET", command, 3) == 0)
{
operation = GET;
}
else if (strncmp("SEND", command, 4) == 0)
{
operation = SEND;
}
else
{
perror("The command must be either GET or SET (case sensitive)\n");
exit(1);
}
// Create the socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot create socket");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
if ((host_info = gethostbyname(host)) == NULL)
{
fprintf(stderr, "Unknown server address\n");
exit(1);
}
bcopy(host_info->h_addr, (char *)&server.sin_addr, host_info->h_length);
// Connecting to the server
if (connect (socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
fprintf(stderr, "Can't connect to server\n");
perror("connect");
exit(1);
}
printf("Connected:\n");
printf("\t\tServer Name: %s\n", host_info->h_name);
pptr = host_info->h_addr_list;
printf("\t\tIP Address: %s\n", inet_ntop(host_info->h_addrtype, *pptr, str, sizeof(str)));
if(operation == SEND)
{
bzero(send_buffer, BUFLEN);
strcpy(send_buffer, "SEND");
send (socket_fd, send_buffer, BUFLEN, 0);
// send the filename to the server
bzero(send_buffer, BUFLEN);
strcpy(send_buffer, filename);
send(socket_fd, send_buffer, BUFLEN, 0);
// read the files contents
FILE *fp;
fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "File '%s' is invalid! Please choose a valid filename\n", filename);
exit(1);
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *string = malloc(fsize+1);
fread(string, fsize, 1, fp);
string[fsize] = 0;
struct sockaddr_in data_conn;
int data_conn_fd;
// establish a client connection on port 6000
if ((data_conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot create data connection socket");
exit(1);
}
bzero((char *)&data_conn, sizeof(struct sockaddr_in));
data_conn.sin_family = AF_INET;
data_conn.sin_port = htons(6000);
bcopy(host_info->h_addr, (char *)&data_conn.sin_addr, host_info->h_length);
if (connect (data_conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
{
fprintf(stderr, "Can't connect to data connection server\n");
exit(1);
}
send(data_conn_fd, string, fsize, 0);
fclose(fp);
//close(data_conn_fd);
}
else if (operation == GET)
{
// not yet implemented
}
else
{
perror("Invalid Operation!\n");
exit(1);
}
fflush(stdout);
close (socket_fd);
return (0);
}
The program has functions to both send a file to the server and receive a file from the server. I've only implemented the send function for now.
Towards the end of the server code the program hangs. The point where I'm printing the file contents to stdout. I'm doing this to test as dumping it into a file is trivial. I've used a printf(“foo”) which prints but it hangs after that. It seems that the while loop corresponding to the send() in the client is not working. It is hanging after that print statement. The rest seems to be working.
Also note that the dual connections is a requirement I cannot use one.
Any help or advice would be very much appreciated.
The receiving loops do not cover the two cases where recv() did not transfer any data.
As there are:
it detected an error and returned -1
it detected the connection had been closed and returned 0
The calls to send() fully ignore the value returned. Do not do this, as
also send() might fail returning -1
also send() might return having sent few data than it was told to send. The code shall loop around send() and count until all data had been sent out.
Related
For instance, there are several requests in a file, and I read them then send to server line by line by using write function. However, there is only one response from server, and I cannot read the whole requests to server. Is there anyone who can help me to figure out this problem. Thank you so much!
There is server code:
<pre> <code>
int main(int argc, char *argv[]){
int sockfd, newsockfd, n;
unsigned int clientLen;
char bufferSK[256];
struct sockaddr_in serv_addr,cli_addr;
FILE *fp = NULL;
//create an endpoint for bind, listen and accept.
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd < 0) {
printf("Failed to create socket for server!\n");
}
bzero((char *)&serv_addr, sizeof(serv_addr));
//set the address of server.
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port_number);
//bind the port with server address
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Error on bind!\n");
}
listen(sockfd,port_number);
printf("\nI am listening for connection\n");
clientLen = sizeof(cli_addr);
//using accept function to accept the connection from client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clientLen);
if (newsockfd < 0) {
printf("Error on accept!\n");
}
printf("\nI have accepted your connection\n");
bzero(bufferSK,256);
n = read (newsockfd, bufferSK,255);
if (n < 0) {
printf("Error reading message from socket\n");
}
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
}
close(newsockfd);
close(sockfd);
return 0;
}
there is client code:
<pre> <code>
FILE *fp_queue;
int main(int argc, char *argv[]){
int sockfd, server_port_number, n, connectRes;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
//Three parameters must be provided.
if(argc != 4){
fprintf(stderr, "Usage: %s server_host_name server_port_number file_path\n",argv[0]);
exit(0);
}
server_port_number = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//create socket for client.
if (sockfd < 0) {
printf("Failed to create socket for client\n");
exit(0);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
printf("Oops! There is no such host!\n");
exit(0);
}
//set the attributes of server as zeros.
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
//copy the server address from serv_addr.sin_addr.s_addr to server->h_adddr.
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(server_port_number);
connectRes = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (connectRes < 0) {
printf("Error connection\n");
exit(0);
}
printf("connect successfully\n");
fp_queue = fopen(argv[3], "r");
if (fp_queue == NULL) {
printf("Failed open client file %s\n", argv[3]);
exit(1);
}
bzero(buffer, 256);
while ((fgets(buffer,sizeof(buffer),fp_queue)) != NULL) {
buffer[strlen(buffer) - 1] = '\0';
printf("buffer is %s\n", buffer);
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
printf("Error write to socket\n");
}
bzero(cliBuffer, 256);
n = read(sockfd, buffer, 256);
if (n <0) {
printf("Error read from socket\n");
}
printf("%s\n", buffer);
}
close(sockfd);
return 0;
}
There are at least 2 design issues in the code.
The server code receives one request, sends a response and then server terminates. If you want to process more requests over one connection then the server code must contain a loop like a client has. The server code should contain something like
while ((n = read (newsockfd, bufferSK, 255) > 0) {
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
break;
}
}
close(newsockfd);
The next problem is that TCP is a stream oriented protocol and your code does not consider that. The stream orientation means that protocol does not keep message boundaries. When a sender calls write("a"); write("b") the receiver may get characters in two separate reads or it may receive 2 characters in one read. To overcome the problem the peers must define some protocol how to determine message boundaries. Usually client sends a message length at begin of message or a control character is used as message boundary or messages have fixed length.
I'm writing the barebones of a web server, but I can't figure out why my file isn't be sent over my socket, I'm connecting to it and everything it just not send()ing my file... What am I missing?
//CODE (server.c)
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(void) {
int create_socket, new_socket;
socklen_t addrlen;
int bufsize = 1024;
char *buffer = malloc(bufsize);
struct sockaddr_in address;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){
printf("The socket was created\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){
printf("Binding Socket\n");
}
long fsize;
FILE *fp = fopen("index.html", "r");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
char *msg = malloc(fsize + 1);
fread(msg, sizeof(msg), 1, fp);
while (1) {
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {
perror("server: accept");
exit(1);
}
if (new_socket > 0){
printf("The Client is connected...\n");
}
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
write(new_socket, "HTTP/1.1 200 OK\n", 16);
write(new_socket, "Content-length: 46\n", 19);
write(new_socket, "Content-Type: text/html\n\n", 25);
/* write(new_socket, "<html><body><H1>Hello world</H1></body></html>",46); */
if((send(new_socket, msg, fsize+1, 0)) > 0){
printf("success");
}
else{
printf("failed");
}
close(new_socket);
}
close(create_socket);
return 0;
}
//FILE (index.html) *same directory
<html>
<body>
<h1>Hello World</h1>
</body>
</html>
The code is completely broken, for a dozen different reasons. Try something more like this instead:
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
bool writeDataToClient(int sckt, const void *data, int datalen)
{
const char *pdata = (const char*) data;
while (datalen > 0){
int numSent = send(sckt, pdata, datalen, 0);
if (numSent <= 0){
if (numSent == 0){
printf("The client was not written to: disconnected\n");
} else {
perror("The client was not written to");
}
return false;
}
pdata += numSent;
datalen -= numSent;
}
return true;
}
bool writeStrToClient(int sckt, const char *str)
{
return writeDataToClient(sckt, str, strlen(str));
}
int main(void){
int create_socket, new_socket;
char *buffer;
int bufsize = 1024;
struct sockaddr_in address;
socklen_t addrlen;
buffer = (char*) malloc(bufsize);
if (!buffer){
printf("The receive buffer was not allocated\n");
exit(1);
}
create_socket = socket(AF_INET, SOCK_STREAM, 0);
if (create_socket == -1){
perror("The socket was not created");
exit(1);
}
printf("The socket was created\n");
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){
perror("The socket was not bound");
exit(1);
}
printf("The socket is bound\n");
long fsize;
FILE *fp = fopen("index.html", "rb");
if (!fp){
perror("The file was not opened");
exit(1);
}
printf("The file was opened\n");
if (fseek(fp, 0, SEEK_END) == -1){
perror("The file was not seeked");
exit(1);
}
fsize = ftell(fp);
if (fsize == -1) {
perror("The file size was not retrieved");
exit(1);
}
rewind(fp);
char *msg = (char*) malloc(fsize);
if (!msg){
perror("The file buffer was not allocated\n");
exit(1);
}
if (fread(msg, fsize, 1, fp) != 1){
perror("The file was not read\n");
exit(1);
}
fclose(fp);
printf("The file size is %ld\n", fsize);
if (listen(create_socket, 10) == -1){
perror("The socket was not opened for listening");
exit(1);
}
printf("The socket is listening\n");
while (1) {
addrlen = sizeof(address);
new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen);
if (new_socket == -1) {
perror("A client was not accepted");
exit(1);
}
printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// I will leave it as an exercise for you to implement
// a proper HTTP request parser here...
int numRead = recv(new_socket, buffer, bufsize, 0);
if (numRead < 1){
if (numRead == 0){
printf("The client was not read from: disconnected\n");
} else {
perror("The client was not read from");
}
close(new_socket);
continue;
}
printf("%.*s\n", numRead, buffer);
if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){
close(new_socket);
continue;
}
char clen[40];
sprintf(clen, "Content-length: %ld\r\n", fsize);
if (!writeStrToClient(new_socket, clen)){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){
close(new_socket);
continue;
}
//if (!writeStrToClient(new_socket, "<html><body><H1>Hello world</H1></body></html>")){
if (!writeDataToClient(new_socket, msg, fsize)){
close(new_socket);
continue;
}
printf("The file was sent successfully\n");
close(new_socket);
}
close(create_socket);
return 0;
}
fsize = ftell(fp);
rewind(fp);
char *filebuff = malloc(fsize + 1);
Why fsize+1? You don't need the +1.
fread(filebuff, sizeof(filebuff), 1, fp);
Unchecked return value. The second argument should be fsize. At present you're only passing the sizeof the pointer.
//create/bind socket
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{
printf("The socket was created\n");
}
If the socket creation fails you must (a) print a proper error message as described below and (b) not just continue with execution as though the error hadn't occurred.
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0)
{
printf("Binding Socket\n");
}
Ditto.
//listen, create new_sock, write headers, send file
while (1){
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
The listen() call should be ahead of the loop, not inside it. This is the first time you've actually handled a failure case.
new_sock = accept(sock, (struct sockaddr *) &address, &addrlen);
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
Invalid. Unchecked return code. The buffer is only valid at all if recv() returned a positive integer, and only that many bytes of it are valid. It should be:
int count = recv(new_socket, buffer, bufsize, 0);
printf("%.*s\n", count, buffer);
Then we start on HTTP:
write(new_sock, "HTTP/1.1 200 OK\n", 16);
write(new_sock, "Content-length: 46\n", 19);
write(new_sock, "Content-Type: text/html\n\n", 25);
The line terminator in HTTP is inherited from Telnet and it is specified as \r\n, not \n.
if(send(new_sock, filebuff, fsize+1, 0) > 0){
printf("success");
}
else{
printf("failed");
}
Inadequate. If you get an error from any system call, you must call perror(), or use errno or strerror() in an error message. "Failed" conveys no useful information, and debugging becomes a mere guessing game. Don't write code like this. You should use perror() or whatever you decide for all the other unchecked return values above.
But there is a bigger problem. You're assuming that the file fits into memory. There is no need for that assumption. Just copy the file using an 8k buffer as follows:
int count;
while ((count = read(in, buffer, sizeof buffer)) > 0)
{
send(out, buffer, count, 0);
}
if (count < 0)
{
perror("send failed");
}
I would avoid stdio for this, it has too many issues, such as the poorly designed fread() and fwrite() function APIs.
Other then the wrong size used in various places (as noted by mathematician1975), your "real" problem is that your trying to communicate with a browser that expects an HTTP server.
HyperText Transfer Protocol is, well, a protocol. It is more complex then a simple connection and a dump of content.
You have to parse the request according to it, and send headers and content in a certain way.
Check to see if bind() is failing and report if so. You're binding to port 80; under Unix-like operating systems only root can bind to reserved ports (less than 1024).
Update 1:
You must initialize addrlen to sizeof(address) before calling accept(). From http://linux.die.net/man/2/accept:
The addrlen argument is a value-result argument: the caller must
initialize it to contain the size (in bytes) of the structure pointed
to by addr; on return it will contain the actual size of the peer
address.
This is not the total code.
This is working fine for normal files like text files, but not working for tar.gz and binary files transfer please help me.
And how to send the chunks of memory using sockets.
server.c
void main()
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char buf[16384];
char remotefile[MAXDATASIZE];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
printf("call binding\n");
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1)
{
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1)
{
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("sigaction");
exit(1);
}
while(1)
{ // main accept() loop
sin_size = sizeof their_addr;
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
perror("accept");
exit(1);
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
if (!fork())
{ // this is the child process
if ((byt=recv(new_fd, remotefile, MAXDATASIZE-1, 0)) == -1)
{
perror("server recv");
exit(1);
}
int serverfile_fd;
size_t result;
printf("\nremotefile in val1 is %s\n",remotefile);
if((serverfile_fd = open(remotefile,O_RDONLY)) < 0)
{
printf("error at remotefile\n");
exit(1);
}
else
{
read(serverfile_fd, &buf[0], sizeof(buf));
}
//printf("file is\n%s", buf);
/* 3. sending buf in val 0*/
if (send(new_fd, buf, 16384, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
client.c
int remote_to_local(const char *remotehost,const char *remotefile,const char *localfile)
{
int sockfd, numbytes,i = 0,j = 0;
char buf[16384];
struct hostent *he;
struct sockaddr_in s_addr; // connector's address information
printf("\n");
printf("Remotehost is %s\n", remotehost);
if ((he=gethostbyname(remotehost)) == NULL)
{ // get the host info
perror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
s_addr.sin_family = AF_INET; // host byte order
s_addr.sin_port = htons(PORT); // short, network byte order
s_addr.sin_addr = *((struct in_addr *)he->h_addr);
//inet_aton(he->h_addr, &s_addr.sin_addr);
memset(s_addr.sin_zero, '\0', sizeof s_addr.sin_zero);
if (connect(sockfd, (struct sockaddr *)&s_addr, sizeof s_addr) == -1)
{
perror("connect");
exit(1);
}
//send(sockfd, remotefile, MAXDATASIZE-1, 0);
val[0] = 1;
printf("Val 0 is %d\n", val[0]);
printf("Val 1 is %d\n", val[1]);
/*1 sending val in r to l*/
if (send(sockfd, val, MAXDATASIZE-1, 0) == -1)
perror("send");
printf("remotefile is %s\n",remotefile);
/* 2 sending remotefile in r to l*/
if (send(sockfd, remotefile, MAXDATASIZE-1, 0) == -1)
perror("send");
/* 3. recieve buf in r to l */
if ((numbytes=recv(sockfd, buf, 16384, 0)) == -1)
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
//printf("Received: \n%s",buf);
int clientfile_fd;
printf("Local file is %s\n",localfile);
if((clientfile_fd = open(localfile,O_CREAT|O_WRONLY,0777)) < 0)
{
printf("error at remotefile\n");
exit(1);
}
else
{
//read(clientfile_fd, &buf[0], sizeof(buf));
int result = strlen(buf);
//printf("Result size is %d\n",result);
open(localfile,O_TRUNC);
write(clientfile_fd, &buf[0], result);
}
close(sockfd);
return 0;
}
Go through ALL your code and fix/change ALL the places where you:
don't correctly handle the results returned by system calls like
recv(). If a positive value is returned, that value is the ONLY safe
way of finding out how much data has been read into the buffer.
Get rid of all the strlen(), printf("%s...) etc. that are either
useless, (the binary data may contain nulls and so the action will
complete early), or dangerous, (binary data contains no nulls at all
and so the calls are UB).
Following logic for receiving a file is already a lot better than what you have. But there are a lot more problems with your code than just this :
FILE *received_file;
received_file = fopen(FILENAME, "w");
...
//copy logic, copies data received from the socket into the file as is.
while (((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
}
fclose(received_file);
close(client_socket);
The receive is continuously called until your receive 0 or a negative number, if you receive 0 that means you need to close the socket because the transfer is finished and the peer has closed its end of the connection too.
The file handle should be created right after accept.
Bottom line is that your code needs a total revision because it is too lengthy for what it is supposed to do, and it is based on totally wrong assumptions. Read first about network programming before attempting anything like this. Socket programming is an advanced topic, without proper understanding you will fail.
I am attempting to create a client/server system that can handle multiple concurrent connections using the unix system call fork.
The client enters a movie title, and the server will check if the movie was there or not. If it was there, it would tell the client the ranking, the name, and the box records.
looking at my forking implementation, the client asks for user input, however the program just simply goes pass it.
OUTPUT EXAMPLE:
connection made with client 127.0.0.1
PID IS 27270
--> all messages read - connection being closed
CLIENT: Please input an string: PID IS 0
At this line, CLIENT: Please input an string: PID IS 0, the user was suppose to input a string, however the program glances over it. How do I make the program take in the string from the client?
SERVER CODE:
int main()
{
int sock, clientsock, mlen, addrsize, msgct, chc, chct, pid;
struct sockaddr_in addr; //ipv4 address
char ch, buf[80];
/*
* Create a socket.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //create socket (AF_NET shows its ipv4 internet connection, SOCK_STREAM shows its a tcp)
if (sock == -1)
{
perror("opening socket");
exit(-1);
}
//Bind socket to local address
/*
* Bind a name to the socket. Since the server will bind with
* any client, the machine address is zero or INADDR_ANY. The port
* has to be the same as the client uses.
*/
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number for local address
addr.sin_addr.s_addr = htonl (INADDR_ANY); //ip address (you can also hard code it)
if (bind(sock, (struct sockaddr *) &addr, //binding, first parameter : is the socket you created, &addr is the
sizeof (struct sockaddr_in)) == -1) //error checking
{
perror ("on bind");
exit (-1);
} //(at this moment we have binded socket)
/*
* Make the socket available for potential clients.
*/
//if there is connection or not?
if (listen(sock,1) == -1)
{
perror("on listen");
exit(-1);
}
//-------Text File Implementation-----------
FILE *fp;
char data[5][200];
char rank[5][2];
char name[5][255];
char value[5][100];
/* opening file for reading */
fp = fopen("movie.txt", "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
fgets (data[0], 200, fp);
int i = 1;
while(fgets (data[i], 200, fp)!=NULL)
{
/* writing content to stdout */
sscanf(data[i],"%s %[^$] %s",rank[i],name[i],value[i]);
puts(data[i]);
i+=1;
}
//CODE DOES NOT IMPLEMENT AFTER THIS WHILE LOOP
//close the file
fclose(fp);
addrsize = sizeof(struct sockaddr_in);
//THIS WHILE LOOP IS NOT BEING IMPLEMENTED...
while(1)
{
clientsock = accept(sock, (struct sockaddr *) &addr, &addrsize);
if (clientsock == -1)//error checking
{
perror("on accept");
exit(-1);
}
printf("connection made with client ");
printf ("%s\n", inet_ntoa (addr.sin_addr)); //also print client address
/* Create child process */
pid = fork();
if (pid < 0)
{
perror("ERROR on fork");
exit(1);
}
if (pid == 0)
{
/* This is the client process */
close(sock);
bool exist = false;
mlen = recv (clientsock, buf, 80, 0);
if (mlen < 0)
{
perror("ERROR reading from socket");
exit(1);
}
int lenS;
int which;
for(int i = 1; i<5; i++)
{
printf("%s\n\n", name[i]);
char *pch = strstr(name[i],buf);
if(pch != NULL)
{
which = i;
exist = true;
puts("GOOD");
}
else
{
puts("bad");
}
}
if(exist)
{
//SEND TO CLIENT FROM HERE!
printf("%s\n", rank[which]);
printf("%s\n", name[which]);
printf("%s\n", value[which]);
lenS = strlen(name[which]);
send (clientsock, name[which], lenS+1, 0);
}
else
{
//SEND TO CLIENT FROM HERE!!!!
printf("NOT HERE ");
send (clientsock, "NOT HERE", 9, 0);
}
printf("Here is the message: %s\n",buf);
exit(0);
}
else
{
close(clientsock);
printf(" --> all messages read - connection being closed\n");
}
}
}
CLIENT CODE:
int main()
{
int sock, addrsize;
struct sockaddr_in addr;
unsigned int in_address;
char buf[80];
int mlen;
/*
* Open a socket for Internet stream services.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //creating a socket to connect to server, AF_INET : ipv4 internet connection, SOCK_STREAM tcp
if (sock == -1)
{ perror("opening socket");
exit(-1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number has to be the same as the one from server
in_address = 127 << 24 | 0 << 16 | 0 << 8 | 1; //ip address, local host, since we are running client and server on the same computer, it needs to have the same ip address
addr.sin_addr.s_addr = htonl (in_address);
if (connect (sock, (struct sockaddr *) &addr, //binding
sizeof (struct sockaddr_in)) == -1)
{
perror("on connect");
exit(-1);
}
char word[100];
int len;
printf("CLIENT: Please input an string: ");
scanf("%s", word);
//printf("You entered: %s\n", word);
len = strlen(word);
send (sock, word, len+1, 0);
mlen = recv (sock, buf, 80, 0);
printf ("%s\n\n\n\n\n\n\n", buf);
/*
* Do a shutdown to gracefully terminate by saying - "no more data"
* and then close the socket -- the shutdown is optional in a one way
* communication that is going to terminate, but a good habit to get
* into.
*/
if (shutdown(sock, 1) == -1)
{
perror("on shutdown");
exit(-1);
}
printf ("Client is done\n");
close(sock);
}
You are running the client and server programs on the same machine, with the same controlling terminal. The server master process, its client-service subprocess(es), and the independent client process therefore may all write to that terminal. They run independently and concurrently, so their outputs can be mashed up.
The fact that the PID IS 0 message is emitted after the prompt does not indicate that the client program has skipped accepting input, which indeed, I don't see how it could do. The prompt and the PID message come from different processes.
It would make things clearer to launch the server process and the client process from separate (virtual) terminals, so that their output is not mixed.
I want to send one text file from client side and want to read the text file on the server side and want to display the texts on the server terminal screen. I have successfully written code for both server and multiple client. I have also sent a text file from client to server side. But now I want to know how to modify the text file and send it and read the text file on server end which is sent from the client side. My server and client code is given below together:
Server and Client Code:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#define filename "//home//myname//Documents//folder1//folder2//input.txt"
#define MAX_CLIENTS 5
//the thread function
void *new_connection_handler(void *);
int main(int argc , char *argv[])
{
//client variables
int sock;
struct sockaddr_in server;
char buffer[256], server_reply[2000];
int len;
//server variables
int socket_desc , client_sock;
struct sockaddr_in client;
socklen_t c = sizeof(client);
//check if the the command contain less than two arguments
if(argc != 2)
{
printf("use either: %s <server/client>\n", argv[0]);
}
// If the command contains minumum 2 arguments
else{
// If argv is client then execute the client code
if(strcmp("client",argv[1]) == 0)
{
/****************/// Client code here **********************************************************************
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
//keep communicating with server
/* Time to send the file */
/******************************************************/
FILE *pf;
int fsize;
pf = fopen(filename, "rb");
if (pf == NULL)
{
printf("File not found!\n");
return 1;
}
else
{
printf("Found file %s\n", filename);
fseek(pf, 0, SEEK_END);
fsize = ftell(pf);
rewind(pf);
printf("File contains %ld bytes!\n", fsize);
printf("Sending the file now\n");
}
while (1)
{
// Read data into buffer. We may not have enough to fill up buffer, so we
// store how many bytes were actually read in bytes_read.
int bytes_read = fread(buffer, sizeof(buffer), 1, pf);
if (bytes_read == 0) // We're done reading from the file
break;
if (bytes_read < 0)
{
error("ERROR reading from file\n");
}
while (bytes_read > 0)
{
int bytes_written = write(sock, buffer, bytes_read);
if (bytes_written <= 0)
{
error("ERROR writing to socket\n");
}
}
}
printf("Done Sending the File!\n");
printf("Now Closing Connection.\n");
/*********************************************************************************/
close(sock);
}
/****************/// Server code here **********************************************************************
// If argv is server then execute the server code
if(strcmp("server", argv[1]) == 0 )
{
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
bzero (&server.sin_zero, 8);
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
//Listen
listen(socket_desc , MAX_CLIENTS);
//Accept and incoming connection
printf("Waiting for incoming connections\n");
c = sizeof(client);
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, &c)) )
{
printf("Connection accepted\n");
pthread_t thread_id;
if( pthread_create( &thread_id , NULL , new_connection_handler , (void*) (intptr_t)client_sock) < 0)
{
perror("could not create thread");
return 1;
}
printf("Handler assigned\n");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
}
}
return 0;
}
void *new_connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = (intptr_t)socket_desc;
int read_size = 0;
char client_message[2000];
//PROBLEM **read the text file sent from client side and display the text on screen**
while( (read_size = recv(sock , client_message , sizeof(client_message) , 0)) > 0 )
printf("Read Text: %.*s", read_size, client_message);
if(read_size == 0)
{
printf("Client disconnected\n");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
You had done some mistakes in your code.
int bytes_read = fread(buffer, sizeof(buffer), 1 ,pf);
This statement is wrong, when you print the bytes_read value it print 1 has a result.If you pass this to next while it will print the h repeatedly.
Use this below statement instead of that fread:
int bytes_read = fread(buffer, 1, sizeof(buffer), pf);
This statement only returns the correct readed value.
while (bytes_read > 0)
{
int bytes_written = write(sock, buffer, bytes_read);
if (bytes_written <= 0)
{
error("ERROR writing to socket\n");
}
}
In this part of the code your program writing the readed content again and again into the socket without break, so the server is print the text without break.
So use this statement after the write() bytes_read=bytes_read-bytes_written; if the read buffer is fully written in your socket it break the statement.
And one more thing is always try to use long data type, when you are trying to use file, because int has lower range compared to long.
UPDATE:
Put the fread(buffer, 1, sizeof(buffer), pf); and try it. It will work.
You can use open() or fopen().
fd=open("filename",O_RDWR);
fd - returns descriptor of the opened file.
O_RDWR - which is used to open file for read and write, you must include fcntl.h.
fp=fopen("filename","r+");
fp - File pointer.
rw - Opened file for both read and write.
File content:
Chandru
ttttt.
After replace:
Stackoverflowt.
Here the content is big so the content is overwritten in the another line.
To avoid that you need to write the changed content in another file.
Writing in another file would be easy to append the text in the line end.