Newsgroup: it.comp.lang.c++
Titolo: Problema con socket

Ciao a tutti,
sto scrivendo una classe che mi permette di semplificare la 
comunicazione client server (semplice scambio di messaggi per il 
momento, poi dovrï¿œ scambiare file).
Ho realizzato 2 semplici programmi di test:
  - un server che accetta le richiesta dal client e riceve un messaggio
  - un client che si collega al server e spedisce un messaggio
fin qui tutto ok.
Quando provo ad implementare la risposta del server, e cioï¿œ a fare una 
cosa del genere:
SERVER:
read...
stampa messaggio ricevuto
write...
CLIENT
write...
read...
stampa messaggio ricevuto
sembra che il tutto vada in stallo. Se killo il client il server termina 
la sua esecuzione stampando effettivamente il messaggio ricevuto, quindi 
sembra che entrambi i processi si blocchino sulle read.
Sapete darmi qualche consiglio?
Grazie!
Simo

 Simo
se magari posti un po' di codice...

 se magari posti un po' di codice...
Certo... eccolo, ma è un po' lungo :-(
/******************************
* Comunicazione.h
*******************************/
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cctype>
#include <unistd.h>
#include "myutils.h"
#define BUFFERSIZE 2000
#include <string>
using namespace std;
class Comunicazione
{
private:
	int sd;
public:
	Comunicazione();
	Comunicazione(int newSd);
	//initClient(char s[], int p);
	void connectToServer(string serverName, int port);
	void initServer(int p);
	int acceptClient();
	string receive();
	void send(string msg);
	void closeComunicazione();
};
/******************************
* Comunicazione.cpp
*******************************/
#include "Comunicazione.h"
Comunicazione::Comunicazione()
{}
Comunicazione::Comunicazione(int newSd)
{
	sd = newSd;
}
void Comunicazione::initServer(int port)
{
	pthread_t tid;
	int err = 0;
	struct sockaddr_in my_addr;
	bzero (&my_addr, sizeof(struct sockaddr_in));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(port );
	my_addr.sin_addr.s_addr = INADDR_ANY;
	sd = socket(AF_INET, SOCK_STREAM, 0);
	if(bind(sd, CAST_ADDR(& my_addr), sizeof(my_addr)) < 0)
		perror("bind failed");
	if(listen(sd, 5) < 0)
		perror("Listen failed");
	printf("Server listening on port %d\n", port);
}
int Comunicazione::acceptClient()
{
	struct sockaddr_in c_add;
	socklen_t addrlen;
	int new_sd = accept (sd, CAST_ADDR(&c_add), &addrlen);
	if(new_sd < 0)
		perror("Accept failed");
	return new_sd;
}
void Comunicazione::connectToServer(string serverName, int port)
{
	struct sockaddr_in s_addr;
	sd = socket(AF_INET, SOCK_STREAM , 0);
	bzero(&s_addr, sizeof(struct sockaddr_in));
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(port);
	struct hostent* server = gethostbyname(serverName.c_str());
	if(server == 0)
		perror("Server not found");
	bcopy((char*) server ->h_addr, (char*)& s_addr.sin_addr.s_addr,
server -> h_length);
	if(connect(sd, CAST_ADDR(& s_addr ), sizeof(struct sockaddr_in)) < 0)
		perror("Connect failed");
}
string Comunicazione::receive()
{
	string retVal="";
	int l = 1;
	char msg[BUFFERSIZE];
	do
	{
		printf("*");
		l = read(sd, msg, BUFFERSIZE - 1);
		if (l<=0)
		{
			if (l<0)
				perror("Read error");
			break;
		}
		msg[l] = 0;
		retVal+=msg;
	}while(l>0);
	return retVal;
}
void Comunicazione::send(string msg)
{
	write(sd, msg.c_str(), strlen(msg.c_str()));
}
void Comunicazione::closeComunicazione()
{
	close(sd);
}
/******************************
* myutils.h
*******************************/
# ifndef __MYUTILS_H__
	# define __MYUTILS_H__
	# include <stdio.h>
	# include <stdlib.h>
	# include <string.h>
	# define CAST_ADDR(x) (struct sockaddr *)(x)
	void sys_err(const char *s);
	void sys_warn(const char *s);
	void user_err(const char *s);
# endif
/******************************
* myutils.cpp
*******************************/
# ifndef __MYUTILS_H__
	# define __MYUTILS_H__
	# include <stdio.h>
	# include <stdlib.h>
	# include <string.h>
	# define CAST_ADDR(x) (struct sockaddr *)(x)
	void sys_err(const char *s)
	{
		perror(s);
		exit(-1);
	}
	void sys_warn(const char *s)
	{
		perror(s);
	}
	void user_err(const char *s)
	{
		printf ("%s\n", s);
		exit(-1);
	}
# endif
/******************************
* testServer.cpp
*******************************/
#include "../include/Comunicazione.h"
#include <iostream>
int main()
{
	Comunicazione mainServer;
	mainServer.initServer(2121);
	Comunicazione slave(mainServer.acceptClient());
	cout<<slave.receive()<<endl;
	sleep(2);
	slave.send("Riciao!");
	slave.closeComunicazione();
	mainServer.closeComunicazione();
}
/******************************
* testClient.cpp
*******************************/
#include "../include/Comunicazione.h"
#include <iostream>
int main()
{
	Comunicazione client;
	client.connectToServer("127.0.0.1", 2121);
	client.send("Ciao!");
	cout<<client.receive()<<endl;
	client.closeComunicazione();
}

 Marco
Se non implemento la risposta del server il server stampa
correttamente quello che ha ricevuto ma molto probabilmente, come dici
tu, il server esce dalla read solo a causa della caduta del client.
Spero sia questa la causa del problema.
Quindi potrei usare un carattere di fine messaggio (0xFF ad esempio)
da inviare in coda?
La receive diventerebbe una cosa del genere:
string Comunicazione::receive()
{
        string retVal="";
        int l = 1;
        char msg[BUFFERSIZE];
        do
        {
                printf("*");
                l = read(sd, msg, BUFFERSIZE - 1);
                if (l<=0)
                {
                        if (l<0)
                                perror("Read error");
                        break;
                }
                if(msg[l-1] == 0xFF)
                {
                      msg[l-1] = "\0";
                      retVal+=msg;
                      return retVal;
                }
                else
                {
                      msg[l] = 0;
                      retVal+=msg;
                }
        }while(l>0);
        return retVal;
}
Però, dovento in futuro inviare file, chi mi garantisce che i file non
contengono il carattere che sceglierò come "fine messaggio"???
Ci sono altre soluzioni?
Grazie 1000 per l'aiuto (devo ancora verificare i tuoi suggerimenti,
ma credo che siano stati fondamentali per capire dove si blocca la
ricezione)
Simo.

 Ci sono altre soluzioni?
Quello che ti ha suggerito Lorenzo Beretta nel ng di C: scriverti un
protocollo. Ad es. la cosa piu' semplice che mi viene in mente e' che prima
mandi un int che dice quanto e' lunga la stringa che segue, cosi' leggi il
numero di caratteri giusti.
BTW, sei sicuro che quello che hai scritto funzioni? A me sembra la stessa
cosa di prima: stai cercando di leggere BUFFERSIZE-1 caratteri, se non ci
sono la read si blocca e non vai piu' avanti.
Pleg
PS: ha senso tenere due discussioni sulla stessa cosa in parallelo su due ng
diversi?

 impostabile), come una select.
Ma così non è poco efficiente??
Se devo trasferire un file di qualche MB mi pare un procedimento
troppo oneroso...