this is my code for the server so far:
a function that finds if a word is in a file:
int Search_in_File_name(char *fname, char *str) {
FILE *fp;
int line_num = 1;
int find_result = 0;
char temp[512];
if((fp = fopen(fname, "r")) == NULL) {
return(-1);
}
while(fgets(temp, 512, fp) != NULL) {
if((strstr(temp, str)) != NULL) {
//printf("\n[copil] logare reusita");
find_result++;
}
line_num++;
}
if(find_result == 0) {
//printf("\nnume incorect");
fclose(fp);
return(3);
}
//Close the file if still open.
if(fp) {
fclose(fp);
}
return(4);
}
and main where i have to look see if a client logs in before doing something else. I used fork for every client that connects to the server. I want to create a file in my project directory for every client and i need the number of the client to do that( or the port specified by "ntohs(newAddr.sin_port)" but i can't obtain the number of the client because i can't declare any int variables.
int main(){
int sockfd, ret;
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Server Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); //asociaza adresa serverAddr(localhost) la socketul creat (sockfd)
if(ret < 0){
printf("[-]Error in binding.\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if(listen(sockfd, 10) == 0){ //marcheaza socketul (sockfd) ca fiind socketul care va accepta o conexiune viitoare si limita maxima de conexiuni in asteptare
printf("[+]Listening....\n");
}else{
printf("[-]Error in binding.\n");
}
while(1){
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size); //ia prima conexiune din lista asociata lui sockfd prin listen si creaza un nou socket si returneaza un descriptor de fisier pentru acel nou socket
if(newSocket < 0){
exit(1);
}
printf("Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
int i=0;
if((childpid = fork()) == 0){
close(sockfd);
int ok=0;
char* nume_fisier;
while(1){
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
break;
}else if(strncmp(c1, buffer, strlen(c1))==0 && ok ==0){
int lungCom, lungNume;
char name[lungNume];
lungCom=strlen(buffer); //lungimea comenzii
lungNume=lungCom-strlen(c1); //lungimea numelui
name[lungNume]='\0';
strncpy(name,&buffer[lungCom-lungNume],lungNume);//pun numele din comanda in variabia name
printf("\n[copil] asta e numele: %s ", name);
printf("\n[copil] %s", w1);
if(Search_in_File_name("nume.txt", name)==4){// daca am gasit numele in lista
i=i+1;
printf("----%d----",i);
send(newSocket, v1, strlen(v1), 0);
bzero(buffer, sizeof(buffer));
ok=1;
printf("\n[copil] am trimis mesajul: %s \n", v1);
}else{ // daca nu am gasit numele in lista
send(newSocket, v2, strlen(v2), 0);
printf("\n[copil] am trimis mesajul: %s \n", v2);
bzero(buffer, sizeof(buffer));
}
}else if(strcmp(buffer, "logout")==0 && ok == 1){
printf("incercare delogare de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("delogat de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
ok=0;
printf("Client: %s\n", buffer);
send(newSocket, d1, strlen(d1), 0);
bzero(buffer, sizeof(buffer));
}else if(strcmp(buffer, "logout")==0 && ok == 0){
printf("incercare delogare de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("Client: %s\n", buffer);
send(newSocket, d2, strlen(d2), 0);
bzero(buffer, sizeof(buffer));
}else if(strcmp(buffer, "cos")==0 && ok == 1){
printf("incercare creare cos de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("Client: %s\n", buffer);
printf("----%d---:", ntohs(newAddr.sin_port));
//nume_fisier=creare_cos_client(nume_client);
//printf("---nume_fisier: %s", nume_fisier);
send(newSocket, cos1, strlen(cos1), 0);
bzero(buffer, sizeof(buffer));
}else{
printf("Client: %s\n", buffer);
send(newSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(newSocket);
return 0;
}
If i delete that "int i=0; " before the fork my program works fine but as soon as i add it back(anywhere) the client can't take any input and the server doesn't check if the name is in the file or not.
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
Two mistakes here:
You ignore the return value of recv. So you have no idea how many bytes you received. How can you do anything useful with some data if you have no idea how much data you have?
You can only pass a C-style string to strcmp. At this point, buffer only contains the raw data you received from the other side. It isn't a C-style string because, by definition, a C-style string has a terminating zero byte.
You have another more fundamental problem though -- your use of strcmp suggests you think you are using a message protocol and have received a message. But you are using TCP and TCP is not a message protocol.
It's hard to say precisely why adding int i =0; saves you from crashing or freezing. But my guess is that the zero just happens to be stored in memory after the buffer and so, by luck, provides the terminating zero byte that strcmp requires. But that's just a guess.
Related
I'm studying sockets and client server communication with select. My problem is that at line 261 i get the Bad File Descriptor error and I have no idea why. The message on line 233 arrives to the client, in the one after (line 252) the client instead of receiving the size in bytes receives 0, and in the write after (line 261) I get the error. I'm really confused.
This is the SERVER
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define DIM_BUFF 100
#define max 10
#define mass(a, b) ((a) > (b) ? (a) : (b))
/********************************************************/
void gestore(int signo) {
int stato;
printf("esecuzione gestore di SIGCHLD\n");
wait(&stato);
}
/********************************************************/
//STRUTTURA DATI
typedef struct{
char Targa[max];
int Patente;
char Tipo[max];
char Folder[max];
}Prenotazione;
//REQUEST DATAGRAM
typedef struct{
char Targa[max];
int newPatente[max];
}Request;
int main(int argc, char **argv) {
//inizializziamo struttura
Prenotazione pren[3];
//dati mock
strcpy(pren[0].Targa,"ciao1");
pren[0].Patente=1234;
strcpy(pren[0].Tipo,"tipo1");
strcpy(pren[0].Folder,"prova1");
strcpy(pren[1].Targa,"ciao2");
pren[1].Patente=1234;
strcpy(pren[1].Tipo,"tipo2");
strcpy(pren[1].Folder,"prova2");
strcpy(pren[2].Targa,"ciao3");
pren[2].Patente=1234;
strcpy(pren[2].Tipo,"tipo3");
strcpy(pren[2].Folder,"prova3");
printf("struttura dati inizializzata!!\n");
int listenfd, connfd, udpfd, nready, maxfdp1;
const int on = 1;
FILE* fd_file;
char zero = '\0' ,Targa[max],fileName[20],path[128];
int buff[DIM_BUFF];
fd_set rset;
int len, nread, nwrite, num, port,count=0;
long size;
struct sockaddr_in cliaddr, servaddr;
Request *req = (Request *)malloc(sizeof(Request));
DIR *dir1;
struct dirent *dd1;
/* CONTROLLO ARGOMENTI ---------------------------------- */
if (argc != 2) {
printf("Error: %s port\n", argv[0]);
exit(1);
}
nread = 0;
while (argv[1][nread] != '\0') {
if ((argv[1][nread] < '0') || (argv[1][nread] > '9')) {
printf("porta non intero\n");
exit(2);
}
nread++;
}
port = atoi(argv[1]);
if (port < 1024 || port > 65535) {
printf("Porta scorretta...");
exit(2);
}
/* INIZIALIZZAZIONE INDIRIZZO SERVER ----------------------------------------- */
memset((char *)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(port);
printf("Server avviato\n");
/* CREAZIONE SOCKET TCP ------------------------------------------------------ */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
perror("apertura socket TCP ");
exit(1);
}
printf("Creata la socket TCP d'ascolto, fd=%d\n", listenfd);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
perror("set opzioni socket TCP");
exit(2);
}
printf("Set opzioni socket TCP ok\n");
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind socket TCP");
exit(3);
}
printf("Bind socket TCP ok\n");
if (listen(listenfd, 5) < 0) {
perror("listen");
exit(4);
}
printf("Listen ok\n");
/* CREAZIONE SOCKET UDP ------------------------------------------------ */
udpfd = socket(AF_INET, SOCK_DGRAM, 0);
if (udpfd < 0) {
perror("apertura socket UDP");
exit(5);
}
printf("Creata la socket UDP, fd=%d\n", udpfd);
if (setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
perror("set opzioni socket UDP");
exit(6);
}
printf("Set opzioni socket UDP ok\n");
if (bind(udpfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind socket UDP");
exit(7);
}
printf("Bind socket UDP ok\n");
/* AGGANCIO GESTORE PER EVITARE FIGLI ZOMBIE -------------------------------- */
signal(SIGCHLD, gestore);
/* PULIZIA E SETTAGGIO MASCHERA DEI FILE DESCRIPTOR ------------------------- */
FD_ZERO(&rset);
maxfdp1 = mass(listenfd, udpfd) + 1;
/* CICLO DI RICEZIONE EVENTI DALLA SELECT ----------------------------------- */
for (;;) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else {
perror("select");
exit(8);
}
}
//GESTIONE RICHIESTE CAMBIO NUMERO PATENTE--------------------
if (FD_ISSET(udpfd, &rset)) {
int result=-1;
printf("Server: ricevuta richiesta di cambio numero patente\n");
len = sizeof(struct sockaddr_in);
if (recvfrom(udpfd, req, sizeof(Request), 0, (struct sockaddr *)&cliaddr, &len) <
0) {
perror("recvfrom");
continue;
}
printf("targa: %s \n", req->Targa);
printf("nuovo numero patente: %s \n", req->newPatente);
for(int i=0;i<3 && result==-1;i++){
if(strcmp(req->Targa,pren[i].Targa)==0){
pren[i].Patente=*req->newPatente;
result=0;
}
}
printf("cambio numero patente effettuato!, invio risposta... \n");
if (sendto(udpfd, &result, sizeof(result), 0, (struct sockaddr *)&cliaddr, len) < 0) {
perror("sendto");
continue;
}
}//IF UDP
//GESTIONE RICHIESTE SCARICAMENTO IMMAGINI
if (FD_ISSET(listenfd, &rset)) {
printf("Ricevuta richiesta di get di un file\n");
len = sizeof(struct sockaddr_in);
if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len)) < 0) {
if (errno == EINTR)
continue;
else {
perror("accept");
exit(9);
}
}
if (fork() == 0) { /* processo figlio che serve la richiesta di operazione */
close(listenfd);
printf("Dentro il figlio, pid=%i\n", getpid());
char Fold[max];
int trovato=-1;
while ((nread = read(connfd, &Targa, sizeof(Targa))) > 0) {
printf("Server (figlio): targa richiesta: %s\n", Targa);
for(int i=0;i<3;i++){
if(strcmp(Targa,pren[i].Targa)==0){
strcpy(Fold,pren[i].Folder);
trovato=i;
}
}
if(trovato>=0){
dir1 = opendir(Fold);
while ((dd1 = readdir(dir1)) != NULL) {
if (strcmp(dd1->d_name, ".") != 0 && strcmp(dd1->d_name, "..") != 0) {
strcpy(fileName, dd1->d_name);
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
path[0] = '\0'; //path reset
sprintf(path, "%s/%s", pren[trovato].Folder, dd1->d_name);
fd_file = fopen(path, "rb");
if (fd_file < 0) {
printf("ERRORE Apertura FILE\n");
}
fseek(fd_file, 0, SEEK_END);
size=ftell(fd_file);
fseek(fd_file, 0, SEEK_SET);
printf("le dimensioni sono: %ld" ,size);
//invio la dimensione
if (write(connfd, &size,sizeof(long))< 0) {
perror("Errore nell'invio della dimensione file\n");
exit(0);
}
/* lettura dal file (a blocchi) e scrittura sulla socket */
printf("Leggo e invio il file richiesto\n");
while (count<size) {
nread = fread(buff, sizeof(int), sizeof(buff),fd_file);
if (nwrite = write(connfd, buff, sizeof(buff)) < 0) {
perror("write");
break;
}
bzero(buff, sizeof(buff));
count=count+nread;
}
printf("Terminato invio file\n");
fclose(fd_file);
}
}//while DD1
strcpy(fileName,"fine");
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
printf("Terminato invio di tutti i file\n");
closedir(dir1);
}//if trovato
else{
strcpy(fileName,"errore");
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
}
}//while richieste
printf("Figlio TCP terminato, libero risorse e chiudo. \n");
close(connfd);
exit(0);
}//FORK
sleep(1);
close(connfd); //padre chiude la socket(non di ascolto)
}//IF TCP
}//for SELECT
}//main
this is the CLIENT
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define DIM_BUFF 100
#define LENGTH_FILE_NAME 20
int main(int argc, char *argv[]) {
int sd, nread, port,count=0;
char nome_file[LENGTH_FILE_NAME],Targa[10];
struct hostent *host;
struct sockaddr_in servaddr;
int c;
long size;
/* CONTROLLO ARGOMENTI ---------------------------------- */
if (argc != 3) {
printf("Error:%s serverAddress serverPort\n", argv[0]);
exit(1);
}
printf("Client avviato\n");
/* PREPARAZIONE INDIRIZZO SERVER ----------------------------- */
memset((char *)&servaddr, 0, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
host = gethostbyname(argv[1]);
if (host == NULL) {
printf("%s not found in /etc/hosts\n", argv[1]);
exit(2);
}
nread = 0;
while (argv[2][nread] != '\0') {
if ((argv[2][nread] < '0') || (argv[2][nread] > '9')) {
printf("Secondo argomento non intero\n");
exit(2);
}
nread++;
}
port = atoi(argv[2]);
if (port < 1024 || port > 65535) {
printf("Porta scorretta...");
exit(2);
}
servaddr.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
servaddr.sin_port = htons(port);
/* CREAZIONE E CONNESSIONE SOCKET (BIND IMPLICITA) ----------------- */
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
perror("apertura socket ");
exit(3);
}
printf("Creata la socket sd=%d\n", sd);
if (connect(sd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) {
perror("Errore in connect");
exit(4);
}
printf("Connect ok\n");
//inizio ciclo richieste
printf("numero della targa o EOF: \n");
while (gets(Targa)) {
if (write(sd, Targa, (strlen(Targa) + 1)) < 0) {
perror("write");
continue;
}
printf("Richiesta della targa %s inviata... \n", Targa);
//ricezione nome file ogni volta
if (read(sd, &nome_file, sizeof(nome_file)) < 0) {
perror("read");
break;
}
while(strcmp(nome_file,"fine")!=0 ){
FILE* f;
printf("il nome del file: %s \n" ,nome_file);
if (read(sd, &size, sizeof(long)) < 0) {
perror("read");
break;
}
if(size==0){
printf("size 0");
exit(1);
}
printf("la size e': %ld" ,size);
f=fopen(nome_file,"wb");
while (count<size){
nread = read(sd, &c, 1);
fwrite(&c,sizeof(int),1,f);
count=count+nread;
}
fclose(f);
printf("immagine ricevuta\n");
if (read(sd, &nome_file, sizeof(nome_file)) < 0) {
perror("read");
break;
}
}
if(strcmp(nome_file,"fine")==0){
printf("tutte le immaigini ricevute\n");
printf("numero della targa o EOF: \n");
}
else{
printf("ERRORE PROTOCOLLO\n");
shutdown(sd, 0);
shutdown(sd, 1);
close(sd);
exit(0);
}
}//whilw
printf("\nClient: termino...\n");
shutdown(sd, 0);
shutdown(sd, 1);
close(sd);
exit(0);
}//main
I've literally tried everything but it doesn't seem to work.
Thanks for your time and sorry form my bad english.
I have to create a multithread TCP/IP server which contains a variable to count the number of clients connected (and those which disconnect) and print the number of clients connected when a client connects to the server.
This is my client.c file:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
while (1) {
printf("> ");
fflush(stdin);
scanf("%s", buffer);
if (nread != -1)
buffer[nread] = '\0';*/
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
and this is my server.c file:
#define PORT 4444
#define MAX_CONNESSIONI 100
typedef struct myStruct {
int clientCollegati;
int clientCheSiSonoScollegati;
pthread_mutex_t mutex; // Creazione del mutex per sincronizzare la struttura
} myStruct;
myStruct *test;
myStruct *initStruct();
void *incrementa(void*);
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
pthread_t tid;
test = initStruct();
if (pthread_create(&tid, NULL, incrementa, NULL) != 0) {
perror("Errore nella creazione del thread t1\n");
exit(1);
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
memset(&serverAddress, '\0', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
bindStatus = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (bindStatus == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
if (pthread_join(tid, NULL)) { // returns 3
perror("pthread_join error\n");
exit(1);
}
printf("There is/are %d client(s) connected\n", test->clientCollegati);
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
myStruct *initStruct()
{
struct myStruct *ptr = malloc(sizeof(myStruct));
ptr->clientCollegati = 0;
ptr->clientCheSiSonoScollegati = 0;
pthread_mutex_init(&ptr->mutex, NULL); // inizializzazione dinamica del mutex
return ptr;
}
void *incrementa(void *ptr)
{
pthread_mutex_lock(&test->mutex);
test->clientCollegati++;
pthread_mutex_unlock(&test->mutex);
pthread_exit(0);
}
Unfortunately this seems not to work properly, ans you can see server output and here client1 and here client2 output
Where's the mistake? I suppose that the problem is when tid finish and a second call to that pthread_join is invoked to a non-existent thread (because there is a single thread)
Your code logic is wrong. You are doing a single pthread_create() and then multiple pthread_join(). If you want to increment the values for every connected client you have to do one pthread_create() after every single successful accept(), followed by one pthread_join(). Note: all this must happen before the call to fork().
Where's the mistake? I suppose that the problem is when tid finish and a second call to that pthread_join is invoked to a non-existent thread (because there is a single thread)
That's exactly what happens. In your current program, the first pthread_join() is successful, and any successive call fails with errno 3 (no such process) because the thread doesn't exist anymore. So you already figured this out. Why are you creating one thread but joining it multiple times if you know that's wrong?
The way your program is written (fork after the increment) also means that there really is no reason at all to use threads to do the increment, and you don't even need the mutex, since only one single thread will access the value at any given time. In other words, your server isn't multithreaded at all. If you only want to do this as an experiment that's ok, but it doesn't make much sense.
What you probably want to do (to have a multithreaded server) is to have one thread per client instead of forking each time, with the client code in the thread function (in that case having a mutex makes sense). Beware though that this does not scale well for large numbers of clients (in general, the classical fork() approach is better, in which case you really don't need any thread).
I googled and stack-overflowed a lot but didn't find any solution. I have a simple echo client-server program in which client sends a word and the server echoes it.
This is my server.c file:
#define PORT 4444
#define MAX_CONNESSIONI 100
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
// Creazione della socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Echo-Server socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
// Riempimento dei campi della struct
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
// Binding della socket all'indirizzo specificato. Associa alla socket un indirizzo in modo da poter essere contattata dai client
if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
// Imposta la socket all'ascolto. I parametri sono il descrittore della socket e la massima lunghezza della coda di connessioni entranti
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
// Accettazione della connessione
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
// Ricezione del messaggio
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
// Invio del messaggio
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
you can compile it using
gcc -o server.out server.c
and execute it using
./server.out
and this is my client.c file:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
// Creazione della socket
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
// Riempimento dei campi della struct
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
// Connessione
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
printf("[+]Connected to Server\n");
printf("[+]Use single-word and :exit to logout\n");
while (1) {
printf("> ");
//fgets(buffer, 1024, stdin); Per ottenere una stringa con gli spazi
fflush(stdin);
scanf("%s", buffer);
// Invio dei dati al server
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
// Per uscire dalla connessione
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
// Riceve i dati dal server
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
you can compile it using gcc -o client.out client.c
and execute it using ./client.out
This works fine.
How can I edit so that I can execute the server on two different computers?
Change INADDR_ANY to your server IP address.
serverAddress.sin_addr.s_addr = inet_addr("192.168.1.20");
I have a simply program with server and client that comunicate with AF_STREAM socket.
Client will can send multiple request to server, and the server response with a string but I don't know the lenght. The client stops in reading when read return 0 and restarts after the server stops the comunication. I don't understand why.
//SEVER
int main(void){
int idSockServer, idSockClient, clientLen;
struct sockaddr_in indirizzoClient, indirizzoServer;
unsigned short richiesta = 0;
char nomeFile[L_STRING], buffer[L_BUFFER];
printf("Inizializzaione del server\n");
idSockServer = socket(AF_INET, SOCK_STREAM, 0);
if(idSockServer == -1){
fprintf(stderr, "Errore socket\n");
exit(EXIT_FAILURE);
}
indirizzoServer.sin_addr.s_addr = htonl(INADDR_ANY);
indirizzoServer.sin_port = htons(5566);
indirizzoServer.sin_family = AF_INET;
if(bind(idSockServer, (struct sockaddr *) &indirizzoServer, sizeof(indirizzoServer))){
fprintf(stderr, "Errore bind\n");
exit(EXIT_FAILURE);
}
if(listen(idSockServer, 5) == -1){
fprintf(stderr, "Errore listen\n");
exit(EXIT_FAILURE);
}
while(1){
printf("[SERVER] Pronto!\n");
clientLen = sizeof(indirizzoClient);
idSockClient = accept(idSockServer, (struct sockaddr *) &indirizzoClient, &clientLen);
if(idSockClient == -1){
printf("[SERVER] Errore alla connessione\n");
continue;
}
read(idSockClient, &richiesta, L_BUFFER);
switch(richiesta){
case 1:
printf("[SERVER] Richiesta 1 accetata, invio risposta\n");
//this simulates the variable lenght string
strcpy(buffer, "un file\n");
write(idSockClient, buffer, L_BUFFER);
break;
}
sleep(6);
close(idSockClient);
}
}
Here the client
//CLIENT
int main(void) {
int sockIdClient, clientLen, file, len;
char buffer[L_BUFFER], nomeFile[L_STRING];
struct sockaddr_in indirizzoClient;
unsigned short scelta, risposta = 0;
sockIdClient = socket(AF_INET, SOCK_STREAM, 0);
if (sockIdClient == -1) {
perror("Errore creazione socket");
exit(EXIT_FAILURE);
}//fine if creazione socket
indirizzoClient.sin_addr.s_addr = htonl(INADDR_ANY);
indirizzoClient.sin_family = AF_INET;
indirizzoClient.sin_port = htons(5566);
if (connect(sockIdClient, (struct sockaddr *) &indirizzoClient, sizeof (indirizzoClient)) == -1) {
perror("Errore connessione al server");
exit(EXIT_FAILURE);
}//fine connect
do {
printf("1) File disponibili\n");
printf("2) Scarica file\n");
printf("0) Esci\n");
printf("Scelta --> ");
scanf("%hu", &scelta);
switch (scelta) {
case 1:
write(sockIdClient, &scelta, sizeof (unsigned short));
len = read(sockIdClient, buffer, L_BUFFER);
while (len > 0) {
printf("%s", buffer);
printf("%d\n", len);
len = read(sockIdClient, buffer, len);
}
break;
case 2:
//This part of code is not managed by Server yet
write(sockIdClient, &scelta, sizeof (unsigned short));
read(sockIdClient, &risposta, sizeof (int));
if (risposta) {
printf("Nome file: ");
leggiStringa(nomeFile, L_STRING);
write(file = sockIdClient, nomeFile, L_STRING);
if (open(nomeFile, O_WRONLY | O_CREAT, "0666") == -1) {
perror("Errore apertura del file");
close(sockIdClient);
exit(EXIT_FAILURE);
}//fine open
len = read(sockIdClient, buffer, L_BUFFER);
while (len > 0) {
write(file, buffer, L_BUFFER);
printf("leggo..\n");
len = read(sockIdClient, buffer, len);
}
close(file);
} else printf("Il server non ha accetato la richiesta\n");
break;
default:
printf("Scelta non valida");
}
} while (scelta != 0);
close(sockIdClient);
}
I'm writing the barebones of a web server, but I can't figure out why my file isn't be sent over my socket, I'm connecting to it and everything it just not send()ing my file... What am I missing?
//CODE (server.c)
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(void) {
int create_socket, new_socket;
socklen_t addrlen;
int bufsize = 1024;
char *buffer = malloc(bufsize);
struct sockaddr_in address;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){
printf("The socket was created\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){
printf("Binding Socket\n");
}
long fsize;
FILE *fp = fopen("index.html", "r");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
char *msg = malloc(fsize + 1);
fread(msg, sizeof(msg), 1, fp);
while (1) {
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {
perror("server: accept");
exit(1);
}
if (new_socket > 0){
printf("The Client is connected...\n");
}
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
write(new_socket, "HTTP/1.1 200 OK\n", 16);
write(new_socket, "Content-length: 46\n", 19);
write(new_socket, "Content-Type: text/html\n\n", 25);
/* write(new_socket, "<html><body><H1>Hello world</H1></body></html>",46); */
if((send(new_socket, msg, fsize+1, 0)) > 0){
printf("success");
}
else{
printf("failed");
}
close(new_socket);
}
close(create_socket);
return 0;
}
//FILE (index.html) *same directory
<html>
<body>
<h1>Hello World</h1>
</body>
</html>
The code is completely broken, for a dozen different reasons. Try something more like this instead:
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
bool writeDataToClient(int sckt, const void *data, int datalen)
{
const char *pdata = (const char*) data;
while (datalen > 0){
int numSent = send(sckt, pdata, datalen, 0);
if (numSent <= 0){
if (numSent == 0){
printf("The client was not written to: disconnected\n");
} else {
perror("The client was not written to");
}
return false;
}
pdata += numSent;
datalen -= numSent;
}
return true;
}
bool writeStrToClient(int sckt, const char *str)
{
return writeDataToClient(sckt, str, strlen(str));
}
int main(void){
int create_socket, new_socket;
char *buffer;
int bufsize = 1024;
struct sockaddr_in address;
socklen_t addrlen;
buffer = (char*) malloc(bufsize);
if (!buffer){
printf("The receive buffer was not allocated\n");
exit(1);
}
create_socket = socket(AF_INET, SOCK_STREAM, 0);
if (create_socket == -1){
perror("The socket was not created");
exit(1);
}
printf("The socket was created\n");
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){
perror("The socket was not bound");
exit(1);
}
printf("The socket is bound\n");
long fsize;
FILE *fp = fopen("index.html", "rb");
if (!fp){
perror("The file was not opened");
exit(1);
}
printf("The file was opened\n");
if (fseek(fp, 0, SEEK_END) == -1){
perror("The file was not seeked");
exit(1);
}
fsize = ftell(fp);
if (fsize == -1) {
perror("The file size was not retrieved");
exit(1);
}
rewind(fp);
char *msg = (char*) malloc(fsize);
if (!msg){
perror("The file buffer was not allocated\n");
exit(1);
}
if (fread(msg, fsize, 1, fp) != 1){
perror("The file was not read\n");
exit(1);
}
fclose(fp);
printf("The file size is %ld\n", fsize);
if (listen(create_socket, 10) == -1){
perror("The socket was not opened for listening");
exit(1);
}
printf("The socket is listening\n");
while (1) {
addrlen = sizeof(address);
new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen);
if (new_socket == -1) {
perror("A client was not accepted");
exit(1);
}
printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// I will leave it as an exercise for you to implement
// a proper HTTP request parser here...
int numRead = recv(new_socket, buffer, bufsize, 0);
if (numRead < 1){
if (numRead == 0){
printf("The client was not read from: disconnected\n");
} else {
perror("The client was not read from");
}
close(new_socket);
continue;
}
printf("%.*s\n", numRead, buffer);
if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){
close(new_socket);
continue;
}
char clen[40];
sprintf(clen, "Content-length: %ld\r\n", fsize);
if (!writeStrToClient(new_socket, clen)){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){
close(new_socket);
continue;
}
if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){
close(new_socket);
continue;
}
//if (!writeStrToClient(new_socket, "<html><body><H1>Hello world</H1></body></html>")){
if (!writeDataToClient(new_socket, msg, fsize)){
close(new_socket);
continue;
}
printf("The file was sent successfully\n");
close(new_socket);
}
close(create_socket);
return 0;
}
fsize = ftell(fp);
rewind(fp);
char *filebuff = malloc(fsize + 1);
Why fsize+1? You don't need the +1.
fread(filebuff, sizeof(filebuff), 1, fp);
Unchecked return value. The second argument should be fsize. At present you're only passing the sizeof the pointer.
//create/bind socket
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{
printf("The socket was created\n");
}
If the socket creation fails you must (a) print a proper error message as described below and (b) not just continue with execution as though the error hadn't occurred.
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0)
{
printf("Binding Socket\n");
}
Ditto.
//listen, create new_sock, write headers, send file
while (1){
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
The listen() call should be ahead of the loop, not inside it. This is the first time you've actually handled a failure case.
new_sock = accept(sock, (struct sockaddr *) &address, &addrlen);
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
Invalid. Unchecked return code. The buffer is only valid at all if recv() returned a positive integer, and only that many bytes of it are valid. It should be:
int count = recv(new_socket, buffer, bufsize, 0);
printf("%.*s\n", count, buffer);
Then we start on HTTP:
write(new_sock, "HTTP/1.1 200 OK\n", 16);
write(new_sock, "Content-length: 46\n", 19);
write(new_sock, "Content-Type: text/html\n\n", 25);
The line terminator in HTTP is inherited from Telnet and it is specified as \r\n, not \n.
if(send(new_sock, filebuff, fsize+1, 0) > 0){
printf("success");
}
else{
printf("failed");
}
Inadequate. If you get an error from any system call, you must call perror(), or use errno or strerror() in an error message. "Failed" conveys no useful information, and debugging becomes a mere guessing game. Don't write code like this. You should use perror() or whatever you decide for all the other unchecked return values above.
But there is a bigger problem. You're assuming that the file fits into memory. There is no need for that assumption. Just copy the file using an 8k buffer as follows:
int count;
while ((count = read(in, buffer, sizeof buffer)) > 0)
{
send(out, buffer, count, 0);
}
if (count < 0)
{
perror("send failed");
}
I would avoid stdio for this, it has too many issues, such as the poorly designed fread() and fwrite() function APIs.
Other then the wrong size used in various places (as noted by mathematician1975), your "real" problem is that your trying to communicate with a browser that expects an HTTP server.
HyperText Transfer Protocol is, well, a protocol. It is more complex then a simple connection and a dump of content.
You have to parse the request according to it, and send headers and content in a certain way.
Check to see if bind() is failing and report if so. You're binding to port 80; under Unix-like operating systems only root can bind to reserved ports (less than 1024).
Update 1:
You must initialize addrlen to sizeof(address) before calling accept(). From http://linux.die.net/man/2/accept:
The addrlen argument is a value-result argument: the caller must
initialize it to contain the size (in bytes) of the structure pointed
to by addr; on return it will contain the actual size of the peer
address.