I am writing c sockets the send a file from client to server. client() is called in main client program while the server() is called in the server program. send_file() is a helper function for client(). I want the server to wait for another client connection after it finishes getting data from the current client.
The first iteration is fine but I am getting error from accept in the SECOND iteration in the server: server: accept: Socket operation on non-socket
What causes the problem?
int send_file(int socket, char *path) {
int len;
char buf[BUF_SIZE];
char size[BUF_SIZE];
struct stat stbuf;
int fd = open(path, O_RDONLY);
fstat(fd, &stbuf);
sprintf(size, "%d", (int)stbuf.st_size);
write(socket, size, BUF_SIZE);
while((len = read(fd, buf, BUF_SIZE)) > 0) {
write(socket, buf, len);
}
close(fd);
return 1;
}
int client(char *src_path, char *dest_path, char *host_ip, int port) {
int sock_fd;
// Create the sock fd
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (inet_pton(AF_INET, host_ip, &server.sin_addr) < 1) {
perror("client: inet_pton");
close(sock_fd);
exit(1);
}
// Connect to the server
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
perror("client: connect");
close(sock_fd);
exit(1);
}
send_file(sock_fd, src_path);
return 0;
}
int server(int port) {
printf("PORT: %d\n", port);
char buf[BUF_SIZE];
int sock_fd, client_fd;
int len;
// Create the socket FD.
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket
if (listen(sock_fd, MAX_BACKLOG) < 0) {
perror("server: listen");
close(sock_fd);
exit(1);
}
while(1) {
socklen_t client_size = sizeof(client);
if ((client_fd = accept(sock_fd, (struct sockaddr *)&client, &client_size)) < 0) {
perror("server: accept");
close(sock_fd);
exit(1);
}
read(client_fd, buf, BUF_SIZE);
int size = atoi(buf);
printf("Size: %d\n", size);
while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
size -= len;
buf[len] = '\0';
printf("%s", buf);
}
close(client_fd);
}
close(sock_fd);
exit(1);
}
You have a buffer overflow in your read code on the server.
while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
size -= len;
buf[len] = '\0';
// ^^^ Boom!!!
printf("%s", buf);
}
If you read BUF_SIZE bytes from the socket, len is BUF_SIZE and then you set the byte at buf[BUF_SIZE] to \0. This must be clobbering the socket file descriptor which is declared straight after the buffer.
I should add, the best way to fix it is probably to declare the buffer with size BUF_SIZE + 1 rather than read BUF_SIZE - 1 bytes because the IO will be a bit more efficient (you are writing in BUF_SIZE chunks).
Related
I'm new to network programming and recently finished reading through Beej's guide. I have a client/server program that I'm trying to get to continuously have the server return the contents of a file when the client requests it.
It works by the client sending the server a file path and the server reading it (if it exists) into a buffer then sending the buffer to the client which just prints the buffer.
It works, but it will only return one file then ignores any following requests. I have to shut down the client and reconnect again for it to work again. I can't figure out why. I've tried implementing select() and used aio_read() over the standard read() and I also forking a process for the send() function. Each of those those experiments had it working exactly the same pretty much.
Anyone have any tips? I'm at a loss where the problem could be.
Client
#define MAXDATASIZE 100 // max number of bytes at once
#define MAXMSG 25
#define MAXDATA 4096
#define SA struct sockaddr
// clean_str: make sure the string doesn't have junk spaces around it
void clean_str(char *s)
{
size_t len = strlen(s);
char tmp[MAXMSG] = {0};
strncpy(tmp, s, len-1);
memset(s, 0, len);
strncpy(s, tmp, len-1);
}
int main(int argc, char **argv)
{
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char file_request[MAXMSG] = {0};
char file_buf[MAXDATA];
if (argc != 3) {
fprintf(stderr, "usage: client <hostname> <port>\n");
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// load the struct
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(EXIT_FAILURE);
}
// loop trhough all results and connect to the first one we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0) {
close(sockfd);
perror("client: connect");
continue;
}
// if we make it here, we've got a connection
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
inet_ntop(p->ai_family, (SA*)&p->ai_addr, s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo);
// stay connect until client exits
int n;
while (1) {
// make sure everything is cleared to minimize issues
memset(file_buf, 0, MAXDATA);
memset(file_request, 0, sizeof MAXMSG);
numbytes = 0;
// get client request from stdin
int b = read(STDIN_FILENO, file_request, MAXMSG);
if (b < 0) {
perror("client: read");
}
clean_str(file_request);
// send the request to the server
if ((numbytes = send(sockfd, file_request, strlen(file_request), 0)) < 0) {
perror("send");
exit(EXIT_FAILURE);
}
// now we wait for a response
while ((n = read(sockfd, file_buf, MAXDATA-1)) > 0)
printf("%s\n", file_buf);
if (n < 0) {
perror("read");
}
}
return 0;
}
Server
#define PORT 3490
#define MAXDATA 4096
#define FILENAME 256
#define SA struct sockaddr // for less messy casting
// get_file: open file, read contents info a buffer, return buffer
char *get_file(const char *path) {
int n, bytes;
static char buf[MAXDATA];
// try to open file
n = open(path, O_RDONLY);
if (n < 0) {
strcpy(buf, "problem opening file");
printf("%s\n", buf);
return buf;
}
// if exists, read it into buffer on
bytes = read(n, buf, sizeof buf-1);
if (bytes < 0) {
strcpy(buf, "problem reading file");
printf("%s\n", buf);
return buf;
}
close(n);
return buf;
}
int main()
{
int sockfd, filefd;
struct sockaddr_in servaddr;
struct sockaddr_storage client_addr;
socklen_t len;
int nbytes;
char file_request[FILENAME]; // buf to hold client's request string
// clear servaddr struct
memset(&servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET; // IPv4 for simplicity
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // use my IP
servaddr.sin_port = htons(PORT); // short, network by order
// create socket file descriptor
// #param3 is the protocol. 0 means TCP
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// bind the socket to the PORT
if (bind(sockfd, (SA*)&servaddr, sizeof servaddr) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
// this prevents the 'bind: address already in use' issue
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
perror("setsocket");
exit(EXIT_FAILURE);
}
if (listen(sockfd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("server running and waiting for connection...\n");
int open = 1; // keep track if there's an accepted() fd
char *open_file;
while (1) {
// clear the file_request buffer
memset(file_request, 0, FILENAME);
memset(&open_file, 0, sizeof open_file);
nbytes = 0;
if (open) {
// we're only going to connect to one client for now
len = sizeof client_addr;
filefd = accept(sockfd, (SA*)&client_addr, &len);
if (filefd < 0) {
perror("accept");
continue;
} else {
printf("connected to a client\n");
open = 0; // keep track that there's an open fd
}
}
// recieve data from a client
if ((nbytes = recv(filefd, file_request, sizeof file_request, 0)) <= 0) {
// got error or connection was closed by client
if (nbytes == 0) {
printf("file-server: client hung up\n");
close(filefd);
open = 1;
continue;
} else {
perror("recv");
close(filefd);
open = 1;
continue;
}
close(filefd);
} else {
// we got some data
// manage it and get file contents
open_file = get_file(file_request);
if (strcmp(open_file, "0") == 0) {
continue;
}
if (send(filefd, open_file, strlen(open_file), 0) < 0) {
perror("send");
continue;
}
}
}
close(sockfd);
return 0;
}
I try to make a Socket client/server bundle running at the same time, passing information to one another. The problem is, after sending the first piece of data from the client, the server returns the answer correctly but becomes stuck on the call to function send(), disabling the ability for the server to receive another data from the client.
I use the following pieces of code in server and client:
Client Code
char requestToSend[1000] = "Some request";
int client_socket;
struct sockaddr_in servaddr;
client_socket = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
connect(client_socket, (SA*)&servaddr, sizeof(servaddr));
char buffer[MAX];
bzero(buffer, sizeof(buffer));
send(server_socket, requestToSend, sizeof(requestToSend), 0);
bzero(requestToSend, sizeof(requestToSend));
while (strcmp(requestToSend, "") == 0) {
recv(server_socket, requestToSend, sizeof(requestToSend), 0);
}
shutdown(client_socket, SHUT_RDWR);
printf("Received: %s", requestToSend); // requestToSend is not the received result!
Server Code
The following code should return "My new result" in response to any request from the client.
while (1) {
int server_socket, client_socket;
struct sockaddr_in server, client;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
printf("Socket creation failed...\n");
} else {
printf("Socket successfully created..\n");
}
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORT);
if ((bind(server_socket, (SA*)&server, sizeof(server))) != 0) {
printf("Socket binding failed...\n");
} else {
printf("Socket successfully bound..\n");
}
if ((listen(server_socket, 5)) != 0) {
printf("Listen failed...\n");
} else {
printf("Server listening..\n");
}
socklen_t len = sizeof(client);
client_socket = accept(server_socket, (SA*)&client, &len);
if (client_socket < 0) {
printf("Server accceptance failed...\n");
} else {
printf("Server acccepted the client..\n");
}
char buffer[MAX];
bzero(buffer, sizeof(buffer));
recv(client_socket, buffer, sizeof(buffer), 0);
strcpy(buffer, "My new result");
send(client_socket, buffer, sizeof(buffer), 0);
shutdown(server_socket, SHUT_RDWR);
}
There are other questions on Stack Overflow mentioning the problem of send() being stuck, but they don't provide an answer to this question.
You should only open and bind the server socket once. The loop should start before the accept() call. And you should close the client socket, not just call shutdown().
When you're sending the reply, you should just send strlen(buffer)+1 bytes, not sizeof(buffer). The latter will send MAX bytes, which will include lots of uninitialized bytes. Adding 1 to strlen() will include the null byte.
int server_socket, client_socket;
struct sockaddr_in server, client;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
printf("Socket creation failed...\n");
} else {
printf("Socket successfully created..\n");
}
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORT);
if ((bind(server_socket, (SA*)&server, sizeof(server))) != 0) {
printf("Socket binding failed...\n");
} else {
printf("Socket successfully bound..\n");
}
if ((listen(server_socket, 5)) != 0) {
printf("Listen failed...\n");
} else {
printf("Server listening..\n");
}
while (1) {
socklen_t len = sizeof(client);
client_socket = accept(server_socket, (SA*)&client, &len);
if (client_socket < 0) {
printf("Server accceptance failed...\n");
} else {
printf("Server acccepted the client..\n");
}
char buffer[MAX];
bzero(buffer, sizeof(buffer));
recv(client_socket, buffer, sizeof(buffer), 0);
strcpy(buffer, "My new result");
send(client_socket, buffer, strlen(buffer)+1, 0);
close(client_socket);
}
The client's recv() loop should loop until it receives 0, which indicates that the server has closed the socket. Each call should append to the buffer, not overwrite it.
char *ptr = requestToSend;
size_t len = sizeof(requestToSend);
int nread;
while ((nread = recv(server_socket, ptr, len, 0)) != 0) {
if (nread < 0) {
perror("recv from server");
exit(1);
}
ptr += nread;
len -= nread;
}
And it should also close the socket, not use shutdown(). shutdown() is generally only used when you want to half-close a socket -- you want to send EOF to the other system, but continue to read its responses.
I am trying to connect to my local UNIX server i made from another remote device. the Server is up and listening to the port i specified. i also added a new firewall rule to open that port but still my client cannot connect. it shows ERROR CONNECTION REFUSED
here is my server code
int main() {
int fd, i,svclient,rval,msg;
int clients[10], num_clients;
fd_set read_set,write_set;
char buf[100];
struct sockaddr_in addr;
if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(4001);
//strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
//strcpy(addr.sun_path, NAME);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(-1);
}
printf("Bind complet...\n");
if (listen(fd, 20) == -1) {
perror("listen error");
exit(-1);
}
num_clients = 0;
int size = sizeof(fd);
while (1) {
int clientfd;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
for (i = 0; i < num_clients; i++) { //at first this part will not excute
FD_SET(clients[i], &read_set);
}
select(fd + num_clients + 1, &read_set, NULL, NULL, NULL);
if (FD_ISSET(fd, &read_set)) {
if ( (clients[num_clients++] = accept(fd,(struct sockaddr*)&client_addr,&addrlen)) == -1) {
perror("accept error");
continue;
}
/*printf("incoming message..................... !\n \n");*/
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
}
for (i = 0; i < num_clients; i++) {
if (FD_ISSET(clients[i], &read_set)) {
msg = read(clients[i], buf, sizeof(buf));
if(msg > 0){
buf[msg] = 0;
int savedclnt = clients[i];
printf("%s \n \n", buf);
/*for(int p=0;p<num_clients;p++)
{
if( clients[p]!= savedclnt){
write(clients[p],buf,msg);
}
}*/
}
}
}
}
}
and my client
int main( )
{
struct uci_context *uci;
uci = uci_init();
int sockfd;
int ret;
struct sockaddr_in dest;
struct addrinfo hint, *res = NULL;
struct hostent *host;
char *hostip;
char *string;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
puts("Unble to create socket");
exit(1);
}
hostip = ucix_get_option(uci, "pack_mon", "pack_monitoring", "address");
string = ucix_get_option(uci, "pack_mon", "pack_monitoring", "port");
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(atoi(string));
memset(&hint, '\0', sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
printf(" %s- %s\n", hostip, string );
if(isdigit(hostip[0])){
ret = getaddrinfo(hostip, NULL, &hint, &res);// this is more efficient than inet_addr
if (ret) {
exit(1);
}
}else if( (host = gethostbyname(hostip)) != 0){
memcpy((char*)&dest.sin_addr , (char*)host->h_addr , (sizeof dest.sin_addr)+1);
}else{
exit(1);
printf("cannot resolve ip address");
}
if ( connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) < 0 )
{
perror("ERROR Connecting" );
exit(1);
}else{
printf("Port number %s is open.....\n",string);
}
char *message;
message = "help";
write(sockfd,message,strlen(message));
close(sockfd);
freeaddrinfo(res);
return 0;
}
FIREWALL RULE
sudo iptables -I INPUT -p tcp --dport 4001 -j ACCEPT
Error is :
192.168.10.155- 4001
ERROR Connecting: Connection refused
and this logs are coming from this codes :
printf(" %s- %s\n", hostip, string );
perror("ERROR Connecting");
exit(1);
Your client has no code to specify the IP address it wants to connect to. All the code that could do that has been commented out.
Update: Now your bug is here:
strncpy((char*)&dest.sin_addr , (char*)host->h_addr , sizeof dest.sin_addr);
The strncpy function is only suitable for C-style strings. You need to use memcpy or something similar. This will only copy part of the IP address if any octet other than its last one (in network byte order) is zero.
Update: Now your bug is here:
printf("%d\n", connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) < 0);
perror("hmmmm" );
exit(1);
This calls connect, then calls printf and then calls perror. The problem is, the call to printf can modify errno even if it succeeds. Thus your call to perror can print a totally irrelevant error message.
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 have the following C server and client:
SERVER
int main(int argc, char **argv) {
int listenfd, connfd, n;
struct sockaddr_in servaddr;
char recvline[1025];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket Error");
exit(1);
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(1024);
if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("Bind Error");
exit(1);
}
if (listen(listenfd, 1024) < 0) {
perror("Listen Error");
exit(1);
}
while(1) {
printf("Waiting connection...\n");
if ((connfd = accept(listenfd, (struct sockaddr *) NULL, NULL)) < 0) {
perror("Accept Error");
exit(1);
}
printf("Waiting for input.\n");
while ((n = read(listenfd, recvline, sizeof(recvline))) > 0) {
recvline[n] = '\0';
if (fputs(recvline, stdout) == EOF) {
fprintf(stderr,"fputs Error\n");
exit(1);
}
}
printf("Read string: %s", recvline);
close(connfd);
}
}
CLIENT
int main(int argc, char **argv) {
int sockfd, connfd, n;
struct sockaddr_in servaddr;
char buff[1025], matricola[15];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket Error");
exit(1);
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1024);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0) {
fprintf(stderr,"inet_pton Error for %s\n", argv[1]);
exit (1);
}
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
fprintf(stderr,"Connect Error\n");
exit(1);
}
printf("Matricola: ");
fflush(stdin);
scanf("%s", matricola);
strcpy(buff, matricola);
if (write(sockfd, buff, strlen(buff)) != strlen(buff)) {
perror("Write Error");
exit(1);
}
close(connfd);
}
I'm under Linux, I can start the server correctly from terminal that starts listening, but when I open another terminal instance and start the client, the server automatically executes the rest of the code and prints Read string: ### (random characters like dirty buffer). Is this because the server is not waiting for the client to write? What am I doing wrong in this code?
What I tought was that the server didn't wait for the client to write something, so I tried to add a sleep(10) before the server's read command, but nothing changes.
EDIT: I edited the read function from
n = read(listenfd, recvline, strlen(recvline) + 1)) > 0
to
n = read(listenfd, recvline, sizeof(recvline))) > 0
But still it doesn't fix the issue.
Change your inner while cycle to read from the connected file descriptor, not the listening file descriptor, like this:
while ((n = read(connfd, recvline, strlen(recvline) + 1)) > 0) {
recvline[n] = '\0';
if (fputs(recvline, stdout) == EOF) {
fprintf(stderr,"fputs Error\n");
exit(1);
}
}
This line
while ((n = read(listenfd, recvline, sizeof(recvline))) > 0) {
tries to read from the listening socket. This does not make sense.
You need to read from the accepted socket. So it should be:
while ((n = read(connfd, recvline, sizeof(recvline))) > 0) {
Moreover it should be
while ((n = read(connfd, recvline, sizeof(recvline) - 1)) > 0) {
as after the read() you do
recvline[n] = '\0';
For the OP's source if you'd have read sizeof recvline bytes recvline[n] would address one behind the last element of recvline.