File size changes after sending it through socket - c

When sending a file through socket from client to server the file size changes. Where the problem may be?
Here is the client's side code:
char chunk[512];
host_info = gethostbyname(server);
if (host_info == NULL) {
perror("get host by name");
exit(errno);
}
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc < 0) {
perror("socket");
exit(errno);
}
server_address.sin_family = host_info->h_addrtype;
memcpy((char *) &server_address.sin_addr.s_addr, host_info->h_addr_list[0], host_info->h_length);
server_address.sin_port = htons(PORT);
if (connect(socket_desc, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
perror("connect");
exit(errno);
}
file_to_send = fopen (lfile,"rb");
if(!file_to_send) {
perror("fopen");
close(socket_desc);
exit(errno);
} else {
long file_size;
fseek (file_to_send, 0, SEEK_END);
file_size = ftell (file_to_send);
rewind(file_to_send);
while(totally_read < file_size){
chunk[0] = '\0';
bytes_read = fread(chunk, sizeof(char), sizeof(chunk), file_to_send);
totally_read += bytes_read;
int sent = send(socket_desc, chunk, bytes_read, 0);
if(sent < 0){
perror("connect");
exit(errno);
}
totally_sent += sent;
printf("read: %7db sent: %7db totally read: %7db totally sent: %7db\n", bytes_read, sent, totally_read, totally_sent);
}
And here is the server side:
char chunk[512];
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket < 0) {
perror("socket");
close(listen_socket);
exit(errno);
}
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(PORT);
if (bind(listen_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
perror("bind");
close(listen_socket);
exit(errno);
}
listen(listen_socket, 5);
client_address_length = sizeof(client_address);
while(1){
connect_socket = accept(listen_socket, (struct sockaddr *) &client_address, &client_address_length);
if (connect_socket < 0) {
perror("accept");
close(listen_socket);
exit(errno);
}
recv_file = fopen(filename,"wb");
int received = 0;
int totally_wrote = 0, totally_received = 0;
while(1){
chunk[0] = '\0';
received = recv(connect_socket, chunk, sizeof(chunk), 0);
if(received < 0) {
perror("recv");
} else if(received > 0) {
int wrote = fwrite(chunk, sizeof(char), received, recv_file);
totally_wrote +=wrote;
totally_received += received;
printf("received: %7db wrote: %7db totally received: %7db torally wrote: %7db\n", received, wrote, totally_received, totally_wrote);
} else {
printf("Complete!\n");
break;
}
}
When sending a text file I get the following output
on the client side:
totally read: 299695b | totally sent: 299695b
but on the server side:
totally received: 303279b | torally wrote: 303279b
I've opened the file with the editor. The transmitted file is practically the same with the source file, except for some strange data in the beginning. The transmitted file 3584 bytes of additionsl binary data in the beginning if the chunk size is 512 bytes. It adds 3840 bytes if i change the chunk size to 256 bytes.

You are not checking the return value from send()
Send() can return any value between -1 and the third (length) argument, inclusive. You assume any return value > 0 to be equal to the 3rd argument. They need not be.
to deal with short send()s (or recv()s (or read() / write()) you'll need something like:
int sent, pos, bytes_read;
bytes_read = fread(chunk, sizeof(char), sizeof(chunk), file_to_send);
totally_read += bytes_read;
for (pos = 0; pos < bytes_read; pos += sent) {
sent = send(socket_desc, chunk+pos, bytes_read-pos, 0)
switch(sent) {
case -1: /* handle errno here, especially EAGAIN/EINTR */
case 0: /*handle EOF here */
break;
default:
break;
}
}
totally_sent += pos;

Related

file server in C doesn't continually return files when requested

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;
}

Weird file output socket file transferring

So, I'm making a socket program to connect two programs and everything works thus far; setting up winsock, connecting and interaction. However, the file being sent over from the client side to the server side has weird characters in it.
Example:
File: test.txt
Contents: Hey, how are you?
** Client sends file over to Server **
Expected Output: Hey, how are you?
Actual Output: 7_ Ä _
Server code:
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
// Start up Winsock
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Memset alternative
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(portNumber);
bind(Socket, (sockaddr*) &addr, sizeof(Addr));
if (listen(Socket, 1) == SOCKET_ERROR) {
printf("Listening error!\n");
} else {
printf("Listening...\n");
}
if (Sub = accept(Socket, (sockaddr*) &incomingAddress, &AddressLen)) {
int Size;
char *Filesize = malloc(MAX_PATH);
if (recv(Socket, Filesize, MAX_PATH, 0)) { // File Size
Size = atoi((const char*) Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = malloc(Size);
int Offset = 0;
while (Size > Offset) {
printf("TESST");
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
if (Amount <= 0) {
printf("Error: " + WSAGetLastError());
break;
} else {
Offset += Amount;
}
}
FILE *File;
File = fopen("test.txt", "wb+");
fwrite(Buffer, 1, Size, File);
fclose(File);
getchar();
closesocket(Socket);
WSACleanup();
}
}
return 0;
}
Client code:
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
IncomingAddress incomingAddress;
int AddressLen = sizeof(IncomingAddress);
WSAStartup(MAKEWORD(2, 2), &Winsock);
if (LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) {
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&addr, sizeof(Addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6000);
if (connect(Socket, (sockaddr*) &addr, sizeof(Addr)) < 0) {
printf("Connection Failed!\n");
getchar();
return 0;
}
char *ClientIP = inet_ntoa(incomingAddress.sin_addr);
int ClientPort = ntohs(incomingAddress.sin_port);
printf("Client connected!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file... \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("test.txt", "rb+");
if (!File) {
printf("Error while reading the file!\n");
getchar();
return 0;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = malloc(Size);
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(socket, cSize, MAX_PATH, 0); // File size
int Offset = 0;
while (Size > Offset) {
int Amount = send(Sub, Buffer + Offset, Size - Offset, 0);
if (Amount <= 0) {
printf("Error: " + WSAGetLastError());
break;
} else {
Offset += Amount;
}
}
free(Buffer);
closesocket(Sub);
closesocket(Socket);
WSACleanup();
printf("File sent!\n");
return 0;
}
You have three problems, one in the client and two in the server.
In the client you are sending the size of the file through Socket, which is correct. But then you use the unconnected and uninitialized socket Sub to send the data of the file.
In the server you have almost the opposite problem, where you attempt to receive both the size and the data through the passive listening socket instead of the accepted connection socket Sub.
Also in the server, if there's an error when reading the data you report it, but then you write data to the file anyway. In this case it will be some uninitialized data of unknown length.
Use correct sockets, and if there's an error don't do things you should not do.
And actually do some error checking. When receiving the size in the server, you don't check for errors, just that the connection wasn't closed by the other end of the connection.

Prob with binary files using sockets

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.

server can't send message to Client over Socket in C

Hi I'm writing 2 Programs (Server, Client) which should communicate with each other over sockets. The Client is able to send its first message to the server with no problem, but when the server tries to answer, the client receives just an empty msg: recv(...) is 0.
The server suddenly stops after the send(...) function is called.
Here is my Code:
Server:
/* Create a new TCP/IP socket `sockfd`, and set the SO_REUSEADDR
option for this socket. Then bind the socket to localhost:portno,
listen, and wait for new connections, which should be assigned to
`connfd`. Terminate the program in case of an error.
*/
struct sockaddr_in sin,
peer_addr;
//-----gen socket-----//
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
bail_out(EXIT_PARITY_ERROR, "could not create Socket");
//-----bind-----//
memset(&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(options.portno);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0)
bail_out(EXIT_PARITY_ERROR, "Failed to bind to Port");
//-----listen-----//
if (listen(sockfd, 5) < 0)
bail_out(EXIT_PARITY_ERROR, "Server can't accepted connection");
//-----accept-----//
int sock_len = sizeof peer_addr;
if ((connfd = accept(sockfd, (struct sockaddr*)&peer_addr, (socklen_t *)&sock_len)) < 0) //fragen
bail_out(EXIT_PARITY_ERROR, "Can't accept connection to Client");
/* accepted the connection */
//Some other Code which has nothing to do with my Error!
/* read from client (WORKS FINE!!)*/
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}
request = (buffer[1] << 8) | buffer[0];
DEBUG("Round %d: Received 0x%x\n", round, request);
/* compute answer */
correct_guesses = compute_answer(request, buffer, options.secret);
if (round == MAX_TRIES && correct_guesses != SLOTS) {
buffer[0] |= 1 << GAME_LOST_ERR_BIT;
}
DEBUG("Sending byte 0x%x\n", buffer[0]);
/* send message to client */
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL) { //Error in this Method!
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "can't send message!");
}
Methods:
static uint8_t *send_to_client(int fd, uint8_t *buffer, size_t n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_send = 0;
do {
ssize_t r = send(fd, buffer + bytes_send, n - bytes_send, 0); //Program stops HERE!
printf("%d\n", (int)r); //This and the following lines will not be executed!
if (r <= 0) {
return NULL;
}
bytes_send += r;
} while (bytes_send < n);
if (bytes_send < n) {
return NULL;
}
return buffer;
}
Client: (Might be usefull)
sockfd = cnt_to_server(argv[1], argv[2]);
uint8_t buffer;
uint16_t msg_buffer;
do
{
msg_buffer = generate_msg(&msg);
printf("Sending byte 0x%x\n", msg_buffer);
if (send_to_server(sockfd, &msg_buffer, WRITE_BYTES) == NULL) //works
error_exit(EXIT_FAILURE, "can't send message!");
if (read_from_server(sockfd, &buffer, READ_BYTES) == NULL) //NULL
error_exit(EXIT_FAILURE, "can't read message!");
printf("received byte 0x%x\n", buffer);
} while (game_continue(buffer, &msg));
(void)close(sockfd);
Methods:
uint8_t* read_from_server(int fd, uint8_t *buffer, int n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_recv = 0;
do {
ssize_t r;
r = recv(fd, buffer + bytes_recv, n - bytes_recv, 0); //0
printf("%d\n", (int)r);
if (r <= 0) {
return NULL;
}
bytes_recv += r;
} while (bytes_recv < n);
if (bytes_recv < n) {
return NULL;
}
return buffer;
}
int cnt_to_server(const char *par_server, const char *par_port)
{
struct sockaddr_in server;
struct hostent *hp;
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error_exit(EXIT_FAILURE, "could not create Socket");
server.sin_family = AF_INET;
if ((hp = gethostbyname(par_server)) == 0)
error_exit(EXIT_FAILURE, "host error!");
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
server.sin_port = htons(parse_port(par_port));
if (connect(sockfd, (struct sockaddr*) &server, sizeof server) < 0)
error_exit(EXIT_FAILURE, "could not connect!");
return sockfd;
}
Thx for helping me out with this!
Change
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL)
to
if (send_to_client(connfd, &buffer[0], WRITE_BYTES) == NULL)
The solution is to use connfd (File descriptor for connection socket) instead of sockfd:
/* read from client */
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}

C, socket programming: Connecting multiple clients to server using select()

I'm trying to make a server that can be connected to by multiple clients. Here's my code so far:
Client:
int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
Server:
int main(int argc, char **argv) {
fd_set fds, readfds;
int i, clientaddrlen;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
struct sockaddr_in serveraddr, clientaddr;
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(6782);
if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,
sizeof(struct sockaddr_in)))
perror("Bind");
if (-1 == listen(serversock, SOMAXCONN))
perror("Listen");
FD_ZERO(&fds);
FD_SET(serversock, &fds);
while(1) {
readfds = fds;
rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (rc == -1) {
perror("Select");
break;
}
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &readfds)) {
if (i == serversock) {
if (numsocks < maxsocks) {
clientsock[numsocks] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
if (clientsock[numsocks] == -1) perror("Accept");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
} else {
printf("Ran out of socket space.\n");
}
} else {
int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
}
}
}
}
close(serversock);
return 0;
}
As soon as a client connects and sends its first message, the server just runs in an infinite loop, and spits out garbage from the message array. recv doesn't seem to receive anything. Can anyone see where i go wrong?
Two issues in your code:
You should do recv(i, ...) instead of recv(clientsock[i], ...)
After that you do not check if recv() failed, and therefore printf() prints out the uninitialised buffer message, hence the garbage in the output
You need to check for limit <= 0 in your read loop, before you call read.
In the while loop for the server, change the code to do recv(i) instead of recv(clientsocks[i]). I have implemented this code and it works with this change.
I replaced the else with the below and it works
} else {
/* int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
memset ( &message[index] , 0, sizeof ( message [index] ) );
while ((in = recv(i, &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
*/
bzero(buf, sizeof(buf));
if ((rval = read(i, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
}
1) It is a good practice to use PF_INET(protocol family) rather than
AF_INET(address family) during the Socket creation .
2) within the while(1) loop
each time it is advisable to make your readfds empty by using FD_ZERO(&readfds).
in the recv() call you should use i rather than clientsocks[i]
you have to check return value of recv is negative(which indicating error in reading) if that is the case you do not have to print the message.
during printing the message make sure the stdout/server is ready for writing anything to it which you can do it by using writefds (3rd argument of select).

Resources