stop and wait in c, infinite timeouts - c

I'm having difficulties with this project. Everything's working except for binary files, probably because they're pretty big and would expect timeouts. The packetErrorSends are similar to send but they randomly drop packets. I only put them in the client side to isolate my problem. The algorithm I'm going for is send a piece of the file, if it receives it, send an 's' and continue reading and send the send piece. If it times out, send an 'e' and then hop in the loop, resend the current piece and recv the next status update. "While" checks the status, decides whether to move on or resend that piece. The problem is when is times out, server gets stuck in that loop resending the last chunk of data and client keeps timing out and sending back 'e's (the purpose of the print statements) Any clue what's happening?
client:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "packetErrorSend.h"
#include <sys/time.h>
ssize_t recvx(int sockfd, void *buf, size_t len) {
int var = recv(sockfd, buf, len, 0);
if(var != -1)
{
return var;
} else {
printf("%s \n","Did not receive.");
exit(1);
}
}
int main(int argc, char *argv[])
{
char buf[MAX_PACKET_DATA_SIZE];
struct addrinfo hints;
struct addrinfo *rp, *result;
int bytes_received = 1;
int s;
char *server;
char *port;
char *file;
int fd = -1; //file descriptor
int bytes_written = 1;
fd_set readfds;
struct timeval tv;
int rv = 0;
int status;
char sendStatus[1];
if (argc==4)
{
server = argv[1];
port = argv[2];
file = argv[3];
}
else
{
fprintf(stderr, "invalid # of arguments\n");
exit(1);
}
/* Translate host name into peer's IP address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to connect */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-client: connect");
exit(1);
}
freeaddrinfo(result);
FD_ZERO(&readfds);
FD_SET(s, &readfds);
packetErrorSend(s, file, strlen(file)+1, 0);
tv.tv_sec = 2;
rv = select(s+1, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred on filename! No data after 2 seconds.\n");
close(s);
exit(0);
} else {
status = recvx(s,buf,1);
}
if(status == 0 || buf[0] == 'e')
{
fprintf(stderr, "Server Error: unable to access file %s \n", file);
close(s);
exit(0);
}
if(buf[0] == 's')
{
fd =open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"%s \n","Client Error: Open failed");
close(s);
exit(0);
}
FD_ZERO(&readfds);
FD_SET(s, &readfds);
bytes_received = MAX_PACKET_DATA_SIZE;
// while(bytes_received >= MAX_PACKET_DATA_SIZE)
while(bytes_received > 0)
{
tv.tv_sec = 3;
rv = select(s+1, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select");
} else if (rv == 0) {
printf("bytes_received in timeout %d \n", bytes_received );
printf("Timeout occurred! No data after 3 seconds.\n");
sendStatus[0] = 'e';
send(s,sendStatus,1,0);
} else {
bytes_received = recvx(s, buf, MAX_PACKET_DATA_SIZE);
printf("%d\n", bytes_received);
sendStatus[0]='s';
packetErrorSend(s,sendStatus,1,0);
}
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
}
if(bytes_received == -1)
{
fprintf(stderr,"%s \n", "Client Error: Error receiving file");
exit(0);
}
if(close(fd) != 0)
{
printf("%s \n", "Client Error: File did not close successfully");
exit(0);
}
close(s);
}
return 0;
}
server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "packetErrorSend.h"
#include <sys/time.h>
#define SERVER_PORT "5432"
#define MAX_PENDING 5
int main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *rp, *result;
char file[MAX_PACKET_DATA_SIZE];
int s, new_s;
int bytes_transferred = 0;
int fd; //file descriptor
char status[1];
/* Build address data structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
/* Get local address info */
if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to perform passive open */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (!bind(s, rp->ai_addr, rp->ai_addrlen))
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-server: bind");
exit(1);
}
if (listen(s, MAX_PENDING) == -1)
{
perror("stream-talk-server: listen");
close(s);
exit(1);
}
freeaddrinfo(result);
/* Wait for connection, then receive and print text */
while(1)
{
for(int i = 0; i < sizeof(file); i++)
{
file[i] = '\0';
}
if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
{
perror("stream-talk-server: accept");
close(s);
exit(0);
}
if ((bytes_transferred = recv(new_s,file,sizeof(file),0)) > 0)
{
fd = open(file,O_RDONLY);
if(fd < 0)
{
perror("open");
status[0] = 'e';
send(new_s,status,1,0);
close(new_s);
exit(0);
}
status[0] = 's';
send(new_s,status,1,0);
int datasent = 0;
bytes_transferred = 1;
while(bytes_transferred > 0)
{
status[0] = s;
bytes_transferred = read(fd,file,MAX_PACKET_DATA_SIZE);
printf("%d\n",bytes_transferred);
datasent = send(new_s,file,bytes_transferred,0);
if (datasent < 0)
{
perror("send");
break;
}
recv(new_s,status,1,0);
printf("before while: %c \n", status[0]);
while(status[0] == 'e')
{
recv(new_s,status,1,0);
send(new_s,file,bytes_transferred,0);
printf("in while: %c \n", status[0]);
}
}
if (bytes_transferred == 0)
{
break;
}
else if(bytes_transferred == -1)
{
perror("read");
close(new_s);
exit(0);
}
}
}
close(fd);
close(new_s);
return 0;
}

Related

TCP Client connecting to two TCP Servers

This is the code of one of the TCP servers (it's also an UDP client but that should not matter) and we call it FS
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int max(int fd, int fd2){
if(fd > fd2) return fd;
else return fd2;
int main(int argc, char *argv[]){
int ASfd, errcode, listenfd, User_fd;
ssize_t n;
socklen_t addrlen, addrlen2;
struct addrinfo hints, hints2, *res, *res2;
struct sockaddr_in addr;
struct sockaddr_in addr2;
fd_set readfds;
int pid;
char* AS_PORT = argv[3];
char* AS_IP = argv[2];
char* FS_PORT = argv[1];
char buffer[364];
char check[4], num_aluno[6], Fname[64], Fcontent[128];
long Fsize;
//TCP SOCKET
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1) exit(1);
memset(&hints2,0,sizeof hints2);
hints2.ai_family=AF_INET;
hints2.ai_socktype=SOCK_STREAM;
hints2.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(NULL,FS_PORT,&hints2,&res2);
if(errcode != 0){
perror("getaddrinfo");
exit(1);
}
n=bind(listenfd,res2->ai_addr, res2->ai_addrlen);
if(n==-1) exit(1);
if(listen(listenfd,10) == -1) exit(1);
ASfd = socket(AF_INET,SOCK_DGRAM,0);
if(ASfd==-1) exit(1);
memset(&hints,0,sizeof hints);
hints.ai_family=AF_INET;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(AS_IP,AS_PORT,&hints,&res);
if(errcode != 0) exit(1);
addrlen=sizeof(addr);
addrlen2=sizeof(addr2);
while(1){
FD_CLR(ASfd,&readfds);
FD_CLR(listenfd,&readfds);
FD_SET(ASfd,&readfds);
select(max(ASfd,listenfd)+1,&readfds,NULL,NULL,NULL);
if(FD_ISSET(ASfd,&readfds)){
n = recvfrom(ASfd,buffer,128,0,(struct sockaddr*)&addr,&addrlen);
if(n == -1) exit(1);
write(1,buffer,strlen(buffer)+1);
}
else if(FD_ISSET(listenfd,&readfds)){
User_fd = accept(listenfd,(struct sockaddr*)&addr2,&addrlen2);
if(User_fd == -1){
perror("accept");
exit(1);
}
if ((pid = fork())==0) {
close(listenfd);
while(1){
read(User_fd,buffer,364);
write(1,buffer,strlen(buffer)+1);
sscanf(buffer,"%s",check);
if(strcmp(check,"UPL")==0){
sscanf(buffer,"%s %s %s %ld %s",check,num_aluno,Fname,&Fsize,Fcontent);
write(1,Fcontent,strlen(Fcontent)+1);
}
}
freeaddrinfo(res);
close(User_fd);
exit(0);
}
}
}
}
This is the code of our second TCP server (it's also an UDP server) and we call it AS
int main(){
int fd, errcode, listenfd, newfd;
ssize_t n;
socklen_t addrlen, addrlen2;
struct addrinfo hints, hints2, *res, *res2;
struct sockaddr_in addr;
struct sockaddr_in addr2;
char buffer[128], buffertroll[128];
fd_set readfds;
int status = 0, rid, vc, new_vc = 0, pid, tid;
char Fop;
char check[4], password[9], num_aluno_s[6], PD_IP[64], PD_PORT[6], path[64], Fname[64];
//TCP SOCKET
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1) exit(1);
memset(&hints2,0,sizeof hints2);
hints2.ai_family=AF_INET;
hints2.ai_socktype=SOCK_STREAM;
hints2.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(NULL,PORT,&hints2,&res2);
if(errcode != 0) exit(1);
n=bind(listenfd,res2->ai_addr, res2->ai_addrlen);
if(n==-1) exit(1);
if(listen(listenfd,10) == -1) exit(1);
//UDP SOCKET (PD)
fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd==-1) exit(1);
memset(&hints,0,sizeof hints);
hints.ai_family=AF_INET;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(NULL,PORT,&hints,&res);
if(errcode != 0) exit(1);
n=bind(fd,res->ai_addr, res->ai_addrlen);
if(n==-1) exit(1);
mkdir("Users",0777);
addrlen=sizeof(addr);
addrlen2=sizeof(addr2);
while(1){
FD_CLR(fd,&readfds);
FD_SET(fd,&readfds);
FD_SET(listenfd,&readfds);
select(max(fd,listenfd)+1,&readfds,NULL,NULL,NULL);
/* PD communication */
if(FD_ISSET(fd,&readfds)){
memset(buffer,0,128);
memset(check,0,4);
n=recvfrom(fd,buffer,128,0,(struct sockaddr*)&addr,&addrlen);
if(n==-1) exit(1);
write(1,buffer,strlen(buffer)+1);
sscanf(buffer,"%s %s %s %s %s",check,num_aluno_s,password,PD_IP,PD_PORT);
/* case "register" message */
if(strcmp(check,"REG")==0){
write(1,"PD: new user, UID=",19);
write(1,num_aluno_s,6);
write(1,"\n",1);
sprintf(path,"Users/%s",num_aluno_s);
mkdir(path,0777);
createPassFile(num_aluno_s,password);
createRegFile(num_aluno_s,PD_IP,PD_PORT);
n = sendto(fd,"RRG OK\n",8,0,(struct sockaddr*)&addr,addrlen);
if(n == -1) exit(1);
}
/* case "exit" message */
if(strcmp(check,"UNR")==0){
sscanf(buffer,"%s %s %s",check,num_aluno_s,password);
memset(buffer,0,128);
status = deleteUser(num_aluno_s, password);
if (status) sprintf(buffer, "RUN OK\n");
else sprintf(buffer, "RUN NOK\n");
n = sendto(fd,buffer,strlen(buffer)+1,0,(struct sockaddr*)&addr,addrlen);
if(n == -1) exit(1);
}
}
/* User communication */
else if(FD_ISSET(listenfd,&readfds)){
newfd = accept(listenfd,(struct sockaddr*)&addr2,&addrlen2);
if(newfd == -1){
perror("accept");
exit(1);
}
if ((pid = fork())==0) {
close(listenfd);
while(1) {
memset(buffer,0,128);
memset(check,0,4);
read(newfd,buffer,128);
write(1,buffer,strlen(buffer)+1);
sscanf(buffer,"%s",check);
if(strcmp(check,"LOG")==0){
sscanf(buffer,"%s %s %s",check,num_aluno_s,password);
memset(buffer,0,128);
status = verifyUser(num_aluno_s, password);
if (status == 1){
sprintf(buffer,"User: login ok, UID=%s",num_aluno_s);
write(1,buffer,strlen(buffer)+1);
memset(buffer,0,128);
sprintf(buffer, "RLO OK\n");
createLogFile(num_aluno_s);
}
else if (status == 0) sprintf(buffer, "RLO NOK\n");
else sprintf(buffer, "ERR\n");
write(newfd,buffer,strlen(buffer)+1);
}
else if (strcmp(check,"REQ")==0){
sscanf(buffer,"%s %s %d %c %s",check,num_aluno_s,&rid,&Fop,Fname);
memset(buffer,0,128);
status = verifyLogin(num_aluno_s);
if (status) {
new_vc = getVC();
if (Fop == 'R' || Fop == 'U' || Fop == 'D') {
sprintf(buffer,"VLC %s %04d %c %s\n", num_aluno_s, new_vc, Fop, Fname);
sprintf(buffertroll,"User: upload req, UID=%s file: %s, RID=%d VC=%04d\n",num_aluno_s,Fname,rid,new_vc);
write(1,buffertroll,strlen(buffertroll)+1);
if (sendto(fd,buffer,strlen(buffer)+1,0,(struct sockaddr*)&addr,addrlen) == -1){
write(newfd,"RRQ EPD\n",9);
}
}
else if (Fop == 'L' || Fop == 'X') {
sprintf(buffer,"VLC %s %04d %c\n", num_aluno_s, new_vc, Fop);
if (sendto(fd,buffer,strlen(buffer)+1,0,(struct sockaddr*)&addr,addrlen) == -1)
write(newfd,"RRQ EPD\n",9);
}
else write(newfd,"RRQ EFOP\n",10);
} else write(newfd,"RRQ ELOG\n",10);
}
else if (strcmp(check,"AUT")==0){
sscanf(buffer,"%s %s %d %d", check, num_aluno_s, &rid, &vc);
if (new_vc == vc){
tid = getVC();
memset(buffertroll,0,128);
sprintf(buffertroll,"User: UID=%s %c, %s, TID=%04d\n",num_aluno_s,Fop,Fname,tid);
write(1,buffertroll,strlen(buffertroll)+1);
memset(buffertroll,0,128);
sprintf(buffertroll,"RAU %04d\n",tid);
write(newfd,buffertroll,strlen(buffertroll)+1);
createTIDFile(Fop,Fname,tid,num_aluno_s);
}
}
else if(strcmp(check,"EXT")==0){
memset(buffertroll,0,128);
if(deleteLogFile(num_aluno_s)==0){
write(newfd,"EXT NOK\n",8);
continue;
}
deleteTIDFile(num_aluno_s);
write(newfd,"EXT OK\n",7);
break;
}
}
freeaddrinfo(res);
close(newfd);
exit(0);
}
}
memset(num_aluno_s,0,6);
memset(password,0,9);
}
freeaddrinfo(res);
close(fd);
return 0;
}
This is the code used to connect to both TCP servers
//AS Connection
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd==-1) exit(1);
memset(&hints,0,sizeof hints);
hints.ai_family=AF_INET;
hints.ai_socktype=SOCK_STREAM;
errcode = getaddrinfo(AS_IP,AS_PORT,&hints,&res);
if(errcode != 0) exit(1);
n = connect(fd,res->ai_addr,res->ai_addrlen);
if(n==-1) exit(1);
//FS Connection
FSfd = socket(AF_INET,SOCK_STREAM,0);
if(FSfd==-1) exit(1);
memset(&hints2,0,sizeof hints2);
hints2.ai_family=AF_INET;
hints2.ai_socktype=SOCK_STREAM;
errcode = getaddrinfo(FS_IP,FS_PORT,&hints2,&res2);
if(errcode != 0){
perror("lmao");
exit(1);
}
n = connect(FSfd,res2->ai_addr,res2->ai_addrlen);
if(n==-1) exit(1);
Right now our client works fine with AS but we can't connect with FS (accept never accepts any connection and it's blocked there) and I can't figure out what I am doing wrong.
FS Code needs to be like this
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int max(int fd, int fd2){
if(fd > fd2) return fd;
else return fd2;
int main(int argc, char *argv[]){
int ASfd, errcode, listenfd, User_fd;
ssize_t n;
socklen_t addrlen, addrlen2;
struct addrinfo hints, hints2, *res, *res2;
struct sockaddr_in addr;
struct sockaddr_in addr2;
fd_set readfds;
int pid;
char* AS_PORT = argv[3];
char* AS_IP = argv[2];
char* FS_PORT = argv[1];
char buffer[364];
char check[4], num_aluno[6], Fname[64], Fcontent[128];
long Fsize;
//TCP SOCKET
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1) exit(1);
memset(&hints2,0,sizeof hints2);
hints2.ai_family=AF_INET;
hints2.ai_socktype=SOCK_STREAM;
hints2.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(NULL,FS_PORT,&hints2,&res2);
if(errcode != 0){
perror("getaddrinfo");
exit(1);
}
n=bind(listenfd,res2->ai_addr, res2->ai_addrlen);
if(n==-1) exit(1);
if(listen(listenfd,10) == -1) exit(1);
ASfd = socket(AF_INET,SOCK_DGRAM,0);
if(ASfd==-1) exit(1);
memset(&hints,0,sizeof hints);
hints.ai_family=AF_INET;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_flags=AI_PASSIVE;
errcode = getaddrinfo(AS_IP,AS_PORT,&hints,&res);
if(errcode != 0) exit(1);
addrlen=sizeof(addr);
addrlen2=sizeof(addr2);
while(1){
FD_CLR(ASfd,&readfds);
FD_CLR(listenfd,&readfds);
FD_SET(ASfd,&readfds);
FD_SET(listenfd,&readfds);
select(max(ASfd,listenfd)+1,&readfds,NULL,NULL,NULL);
if(FD_ISSET(ASfd,&readfds)){
n = recvfrom(ASfd,buffer,128,0,(struct sockaddr*)&addr,&addrlen);
if(n == -1) exit(1);
write(1,buffer,strlen(buffer)+1);
}
else if(FD_ISSET(listenfd,&readfds)){
User_fd = accept(listenfd,(struct sockaddr*)&addr2,&addrlen2);
if(User_fd == -1){
perror("accept");
exit(1);
}
if ((pid = fork())==0) {
close(listenfd);
while(1){
read(User_fd,buffer,364);
write(1,buffer,strlen(buffer)+1);
sscanf(buffer,"%s",check);
if(strcmp(check,"UPL")==0){
sscanf(buffer,"%s %s %s %ld %s",check,num_aluno,Fname,&Fsize,Fcontent);
write(1,Fcontent,strlen(Fcontent)+1);
}
}
freeaddrinfo(res);
close(User_fd);
exit(0);
}
}
}

How to connect clients two by two as they connect

I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.
example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.
Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.
I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.
Here is my server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "8888"
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
fd_set master;
fd_set read_fds;
int fdmax;
int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;
char buf[256];
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1;
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Server msg: bind failed\n");
exit(2);
}
freeaddrinfo(ai);
puts("Bind success");
if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");
FD_SET(listener, &master);
fdmax = listener;
for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %d\n", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lost\n", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{
for(j = 0; j <= fdmax; j++)
{
if (FD_ISSET(j, &master))
{
if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}
return 0;
}
And here is my client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>
#define PORT "8888"
#define MAXDATASIZE 100
#define MAXNAMESIZE 25
void *receive_handler(void *);
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr,"Usage: ./client address\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("Client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("Client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Client: connection failed\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %s\n", s);
freeaddrinfo(servinfo);
puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;
if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");
puts("Welcome!\n");
puts("[Type '/quit' to quit the chatroom]");
for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);
memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);
if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;
int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;
for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '\0';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);
}
pthread_join(recv_thread , NULL);
close(sockfd);
return 0;
}
void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;
for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '\0';
printf("%s", buffer);
}
}
Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.
What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.
I think the rest depends on further details you should specify in your question.
Let me know
If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.

File transfer from Server to Client in C programming

for some reason, it's not transferring content over. I had strlen(file) in the send() function and it was working for txt file. It won't work with bin files though, so I changed it to bytes_read. Now nothing's transferring properly. I'm getting blank files on the client side. Also, in debugging with print statements, I noticed the bin file is skipping the read() while loop. Any ideas?
Here's my client:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "packetErrorSend.h"
#include <sys/time.h>
#define MAX_LINE 1000
ssize_t recvx(int sockfd, void *buf, size_t len) {
int var = recv(sockfd, buf, len, 0);
if(var != -1)
{
return var;
} else {
printf("%s \n","Did not receive.");
exit(1);
}
}
int main(int argc, char *argv[])
{
char buf[MAX_LINE];
struct addrinfo hints;
struct addrinfo *rp, *result;
int bytes_received = 1;
int s;
char *server;
char *port;
char *file;
int fd = -1; //file descriptor
int bytes_written = 1;
if (argc==4)
{
server = argv[1];
port = argv[2];
file = argv[3];
}
else
{
fprintf(stderr, "invalid # of arguments\n");
exit(1);
}
/* Translate host name into peer's IP address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to connect */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-client: connect");
exit(1);
}
freeaddrinfo(result);
/*send lines of text */
send(s, file, sizeof(file)+30, 0);
int status = recv(s,buf,1,0);
if(status == 0 || buf[0] == 'e')
{
fprintf(stderr, "Server Error: unable to access file %s \n", file);
close(s);
exit(0);
}
if(buf[0] == 's')
{
while(bytes_received != 0)
{
bytes_received = recvx(s, buf, 20);
if(bytes_received == -1)
{
fprintf(stderr, "Client Error: Error receiving file \n");
exit(0);
} else {
if(fd == -1)
{
fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"Client Error: Open failed \n");
break;
}
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
} else {
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
}
}
}
}
if(close(fd) != 0)
{
printf("%s \n", "Client Error: File did not close successfully");
exit(0);
}
close(s);
return 0;
}
Server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/sendfile.h>
#include "packetErrorSend.h"
#define SERVER_PORT "5432"
#define MAX_LINE 2000
#define MAX_PENDING 5
int main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *rp, *result;
char file[MAX_LINE];
int s, new_s;
int bytes_transferred = 0;
int fd; //file descriptor
char status[1];
int bytes_read = 0;
/* Build address data structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
/* Get local address info */
if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to perform passive open */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (!bind(s, rp->ai_addr, rp->ai_addrlen))
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-server: bind");
exit(1);
}
if (listen(s, MAX_PENDING) == -1)
{
perror("stream-talk-server: listen");
close(s);
exit(1);
}
freeaddrinfo(result);
/* Wait for connection, then receive and print text */
while(1)
{
for(int i = 0; i < sizeof(file); i++)
{
file[i] = '\0';
}
if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
{
perror("stream-talk-server: accept");
close(s);
exit(0);
}
while(bytes_transferred == recv(new_s,file,sizeof(file),0))
{
if(bytes_transferred == -1)
{
close(new_s);
exit(0);
}
}
fd =open(file,O_RDONLY);
if(fd < 0)
{
status[0] = 'e';
send(new_s,status,sizeof(status),0);
close(new_s);
exit(0);
}
else
{
status[0] = 's';
send(new_s,status,sizeof(status),0);
while(bytes_read == read(fd,file,sizeof(file)) > 0)
{
if(bytes_read < 0)
{
close(new_s);
exit(0);
}
}
while((bytes_transferred = send(new_s,file,bytes_read,0)) > 0)
{
if(bytes_transferred == -1)
{
close(new_s);
exit(0);
}
}
if(close(fd) != 0)
{
close(new_s);
exit(0);
}
else{
break;
}
}
}
close(new_s);
return 0;
}
Usual copy loop problem:
while((bytes_transferred == send(new_s,file,sizeof(file),0)) > 0)
should be
while((bytes_transferred = send(new_s,file,bytes_read,0)) > 0)
Detailed commentary on your code:
send(s, file, sizeof(file)+30, 0);
should be
send(s, file, strlen(file)+1, 0);
Then:
while(bytes_received != 0)
{
bytes_received = recvx(s, buf, 20);
if(bytes_received == -1)
{
fprintf(stderr, "Client Error: Error receiving file \n");
exit(0);
} else {
if(fd == -1)
{
fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"Client Error: Open failed \n");
break;
}
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
} else {
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
}
}
}
A much simpler way to write all this would be:
fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"Client Error: Open failed %s\n", strerror(errno));
break;
}
while((bytes_received = recvx(s, buf, sizeof buf)) > 0)
{
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s %s\n", "Client Error: Write error", strerr(errno));
break;
}
}
}
}
if(bytes_received == -1)
{
fprintf(stderr, "Client Error: Error receiving file %s\n", strerr(errno));
exit(0);
}
In the server, your code inside the accept loop is totally bizarre. It can be reduced to:
// receive a target file name
if ((bytes_transferred = recv(new_s,file,sizeof(file),0) > 0)
{
fd = open(file,O_RDONLY);
if(fd < 0)
{
perror("open");
status[0] = 'e';
send(new_s,status,1,0);
close(new_s);
exit(0);
}
status[0] = 's';
send(new_s,status,1,0);
while ((bytes_read = read(fd, file, sizeof file)) > 0)
{
if (send(new_s,file,bytes_read,0) < 0)
{
perror("send");
break;
}
}
if (bytes_transferred == 0)
{
break;
}
else if(bytes_transferred == -1)
{
perror("read");
close(new_s);
exit(0);
}
}
close(new_s);
E&OE
Note that you don't have to length-check send() in blocking mode. Posix requires that it blocks until all data has been transferred.
In your code, sizeof(file) is always MAX_LINE, hence the garbage at the end. Because sizeof cares nothing about what you put into variables; it only cares about their in-memory size:
#define MAX_LINE 2000
// ...
char file[MAX_LINE]; // sizeof(file) == 2000
Also, this line is writing beyond the length of the file array, and probably zeroing out some other variable that you care about:
file[sizeof(file)]='\0'; // very bad idea
To fix your initial problem, measure what your are sending (use strlen, or even better, strnlen) - and send only those bytes, including the terminating '\0' , instead of always sending MAX_LEN.
EDIT: after multiple downvotes, apparently due to not warning against the use of strlen & co. when used on non-textual inputs, I will now warn against the use of strlen for non-textual inputs:
do not use strlen unless your input is 100% text.
do not use it anyway, even with text: strnlen is safer, as it will never overflow the buffer (as long as the maximum-length parameter is correctly set):
char line[MAX_LINE];
// ... read into line somehow
int line_length = strnlen(line, MAX_LINE-1);
// make sure that it is 0-terminated
line[line_length] = 0;
To send binary data, you need to measure it first. File sizes can be measured using fseek and ftell. Do not try to use string functions (such as strnlen) or print (printf) binary data, as many bytes will map to control characters and mess up the display. If you need to print binary data, use code similar to this one.

trying to send a mmaped file in chat using sockets in c

my assignment was to build a chat server and client with the beej's guide examples so the client can upload a file to the server.
the instructions were to mmap the file and send the data using send().
iv'e tried first just to send simple txt file but it wont work.
for some reason when debug the program and execcutes it line by line it works.
maybe someone can point out what am i missing?
client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT "6667" // the port client will be connecting to
#define MAXDATASIZE 256 // max number of bytes we can get at once
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct stat mystat;
char* pmap;
int fdin;
if (argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
FD_SET(sockfd,&master);
FD_SET(0,&master);
for(;;)
{
read_fds = master;
if (select(sockfd+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
if (FD_ISSET(0,&read_fds))
{
//reads messege form user
scanf ("%[^\n]%*c", buf);
//if it is upload
if (0 == strncmp(buf,"/upload ",8)) {
//sendFile(sockfd,buf);
if (send(sockfd,buf ,strlen(buf),0) == -1)
perror("send");
if ((fdin = open(buf + 8,O_RDONLY)) < 0)
perror("open");
fstat (fdin,&mystat);
pmap = mmap (0, mystat.st_size, PROT_READ, MAP_SHARED, fdin, 0);
if (send(sockfd,pmap,(int)mystat.st_size,0))
perror("send");
close(fdin);
}
else if (send(sockfd,buf,strlen(buf),0) == -1)
perror("send");
}
else if (FD_ISSET(sockfd, &read_fds))
{
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("%s\n",buf);
}
}
close(sockfd);
return 0;
}
server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libgen.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#define PORT "6667" // port we're listening on
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
struct User *usersPtr = NULL; //ptr to users list
struct File *filesPtr = NULL; //ptr to files list
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
char msg[256]; //string to deal with message
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR, below
int i, j, rv;
struct addrinfo hints, *ai, *p;
char path[100],data[1000];
int fdout;
char* pmap;
int pid;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
// lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
// if we got here, it means we didn't get bound
if (p == NULL) {
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); // all done with this
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,(struct sockaddr *)&remoteaddr,&addrlen);
if (newfd == -1) {
perror("accept");
}
else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",inet_ntop(remoteaddr.ss_family,get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),newfd);
}
}
else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
}
else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
}
else { // we got some data from a client
buf[nbytes] = '\0';
else if (0 == strncmp(buf,"/upload ",8)) {
sprintf(path,"%s",basename(buf + 8));
if((fdout = open (path, O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0)
perror("open");
if ((nbytes = recv(i,data,sizeof data,0)) == -1)
perror("recive");
data[nbytes] = '\0';
lseek (fdout, nbytes - 1, SEEK_SET);
write (fdout, "", 1);
pmap = mmap (0, nbytes, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
memcpy (pmap , data, nbytes);
close(fdout);
}
else {
for(j = 0; j <= fdmax; j++) { // send to everyone!
if (FD_ISSET(j, &master)) {
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)
return 0;
}
Sockets are streams of data, sending 30 bytes then 100 will not result in the server reading 30 bytes then 100, it could read any amount up to 130 bytes. If your file is short, you will probably get the command and the data in one recv.
To get it working for short files containing text (not the complete solution).
The command must be \0 terminated for strlen to give the right size in the server so in the client change:
if (send(sockfd,buf ,strlen(buf),0) == -1)
to
if (send(sockfd,buf ,strlen(buf)+1,0) == -1)
The server will get the command and data together in buf, so in the server change:
char path[100],data[1000];
to
char path[100], *data;
and use data to point to the data in the buffer by changing:
if ((nbytes = recv(i,data,sizeof data,0)) == -1)
perror("recive");
data[nbytes] = '\0';
to
buf[nbytes] = '\0';
data = buf + strlen(buf) + 1;
nbytes = strlen(data);
The full solution is to loop receiving data and to look for the /upload command in stream. You could still look for the \0 as a delimiter, but you should then send the length of the file and use this to determine the number of bytes to read. This will cope with binary files too.

recv() read() and send() without waiting

I am learning how to program a Server TCP socket wherein clients can connect to and wait for commands...
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
do {
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
I just get the part of the code where I'm having problem. I'm reading from a pipe. I'm using that to send messages to the client.. but my problem is with recv. it waits for data sent by client before it sends the data read from my pipe to the client. What i want to happen is everytime i send a data to my pipe it goes directly to the client without waiting for recv.. How can this be done?
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
typedef struct SERVER_FD{
int sPort;
int serverFD;
int smaxFD;
int newFD;
}sSD;
int cFD,
dSize,
err,
start = 1,
state,
DescRead,
DCSERVER = FALSE;
struct sockaddr_in addr, cli_addr;
unsigned long ip;
char strbuf[256];
socklen_t clilen;
fd_set fdin, fduse;
pid_t pid, sid;
int fd=-1;
int nbytes;
char buffer[256];
void process(int ServerFD, int Port, int sMax, int NewSFD);
void cleanUP(int i, int max);
void dlogs(unsigned long ip);
void daemonize();
main (int argc, char *argv[])
{
sSD link;
sSD *sCon;
sCon = &link;
sCon->sPort = 53234;
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
printf("Starting Server-G\n");
fcntl(fd, F_SETFL,
fcntl(fd, F_GETFL) | O_NONBLOCK);
sCon->serverFD = socket(AF_INET, SOCK_STREAM, 0);
if (sCon->serverFD != -1) {
err = setsockopt(sCon->serverFD, SOL_SOCKET, SO_REUSEADDR,(char *)&start, sizeof(start));
if (err != -1) {
err = ioctl(sCon->serverFD, FIONBIO, (char *)&start);
if (err != -1){
process(sCon->serverFD,sCon->sPort,sCon->smaxFD,sCon->newFD);
}
else{
perror("ioctl() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("setsockopt() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("FAILED CONNECTING TO SOCKET");
exit(EXIT_FAILURE);
}
}
void process(int ServerFD, int Port, int sMax, int NewSFD){
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = 0;
addr.sin_port = htons(Port);
err = bind(ServerFD,(struct sockaddr *)&addr, sizeof(addr));
if (err < 0) {
perror("bind() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
daemonize();
err = listen(ServerFD, 32);
if (err < 0) {
perror("listen() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
clilen = sizeof(cli_addr);
FD_ZERO(&fdin);
sMax = ServerFD;
FD_SET(ServerFD, &fdin);
do {
fduse = fdin;
err = select(sMax + 1, &fduse, NULL, NULL, NULL);
if (err < 0) {
perror(" select() failed");
break;
}
DescRead = err;
for (cFD=0; cFD <= sMax && DescRead > 0; ++cFD) {
if (FD_ISSET(cFD, &fduse)) {
DescRead -= 1;
if (cFD == ServerFD) {
do {
NewSFD = accept(ServerFD,(struct sockaddr *) &cli_addr, &clilen);
if (NewSFD < 0) {
if (errno != EWOULDBLOCK) {
perror(" accept() failed");
DCSERVER = TRUE;
}
break;
}
ip = ntohl(cli_addr.sin_addr.s_addr);
printf(" Connection from %d.%d.%d.%d\n",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
dlogs(ip);
FD_SET(NewSFD, &fdin);
if (NewSFD > sMax)
sMax = NewSFD;
} while (NewSFD != -1);
}
else {
state = FALSE;
do {
//PART WHERE I'm Having problems.
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
if (state) {
close(fd);
close(cFD);
FD_CLR(cFD, &fdin);
if (cFD == sMax) {
while (FD_ISSET(sMax, &fdin) == FALSE)
sMax -= 1;
}
}
}
}
}
} while (DCSERVER == FALSE);
cleanUP(cFD, sMax);
}
void cleanUP(int i, int max){
for (i=0; i <= max; ++i) {
if (FD_ISSET(i, &fdin))
close(i);
}
}
void dlogs(unsigned long ip){
FILE* pFile = fopen("/sockF.txt", "a+");
fprintf(pFile,"Connection from: %d.%d.%d.%d",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
fclose(pFile);
}
void daemonize(){
pid = fork();
if(pid<0){
perror("fork() failed");
exit(EXIT_FAILURE);
}
if(pid>0){
exit(EXIT_SUCCESS);
}
umask(0);
sid = setsid();
if(sid<0){
perror("setsid() failed");
exit(EXIT_FAILURE);
}
if((chdir("/")) < 0){
perror("failed changing directory");
exit(EXIT_FAILURE);
}
}
Sample Output: I am using telnet and putty to test Server
From Telnet: IP: 192.168.5.53
Telnet 192.168.5.55 53234
./socks
Starting Server-G
Connection from: 192.168.5.53
Now When telnet is connected i use putty to send data to the pipe so the server will read it.
From Putty:
echo "TEST" > /tmp/myFIFO
the problem here is that whenever i send the data from putty writing to the pipe the server waits for telnet to send data before it outputs and send the data i've written to the pipe. How can i make both recv and read work at the same tym so when i write to my pipe it will output without waiting for recv?
Thanks
EDIT: I've also used thread to read the pipe but it still waits recv() before the server output what have been read to the pipe.
Use select or poll to wait for events on both of your file handles, eg. (using poll)
#include <poll.h>
//...
struct pollfd pfds[2];
int rc;
/* Wait for input on either one of the fds */
pfds[0].fd = fd;
pfds[0].events = POLLIN;
pfds[1].fd = cFD;
pfds[1].events = POLLIN;
do {
/* Wait forever for something to happen */
rc = poll(&pfds, 2, -1);
/* Error handling elided */
if (pfds[0].revents & POLLIN)
{
/* Read from fd, change pfds[1].events to (POLLIN | POLLOUT) so you know when you
can write without blocking. also clear pfds[0].events so we don't read until we
write */
pfds[0].events = 0;
pfds[1].events = POLLIN | POLLOUT;
}
if (pfds[1].revents & POLLIN)
{
/* Read from socket */
}
if (pfds[1].revents & POLLOUT)
{
/* write to socket, reset events flags */
pfds[0].events = POLLIN;
pfds[1].events = POLLIN;
}
} while (1)

Resources