Prosty program klient - serwer. Co mam nie tak ?

0

Witam,

To mój pierwszy post na tym forum więc najpier chciałem wszystkich powitać ;).

Mam problem z bardzo prostym programikiem typu klient - serwer. Problem polega na tym, że proces serwera nie otrzymuje danych (tutaj znak - typ char) dopóki (i tutaj uwaga) nie włącze whireshark-a O_o (wireshark ustawiony jest na interfejs any w trybie promiscous). Możecie mi pomóc ? Poniżej załączam kod klienta i serwera. Moje środowisko to: ArchLinux x64, kompilator gcc, IDE KDevelop4.
Klient

/* proces klienta */
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#define SIZE sizeof(struct sockaddr_in)

int sockfd;

void catcher(int signo);

int main() {

  char c, rc;
  //struktura sygnalu doobsługi
  static struct sigaction act;
  act.sa_handler=catcher;
  sigfillset(&(act.sa_mask));
  sigaction(SIGALRM, &act, NULL);
   //zainicjuj gniazdo internetowe z umuerem portu 7000
  struct sockaddr_in server={AF_INET, 7000};
  //przekształs adres serwera i zapamietaj IP
  server.sin_addr.s_addr= inet_addr("10.43.12.6");
  //ustaw punk koncowy transportu
  if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("socket failed");
    exit(1);
  }
  //polacz gniazdo z adresem serwera
  if(connect(sockfd, (sockaddr*)&server, SIZE) == -1)
  {
    perror("connect failed");
    exit(1);
  }
  //wysyłaj i odbieraj dane z serwera
  for(rc='\n';;)
  {
    if(rc == '\n')
      printf("Entetr downcase letter:");
    c=getchar();

    if(send(sockfd, &c, 1, 0) == -1)
    {
      perror("send failed");
      exit(1);
    }
    printf("Send: %c\n",c);
    alarm(5);//ustaw alarm
    if(recv(sockfd, &rc, 1, 0) > 0)
    {
      printf("%c", rc);
      alarm(0);//usuń alarm
    }
    else
    {
      printf("server died\n");
      close(sockfd);
      exit(1);
    }
  }
}

void catcher(int signo)
{
  close(sockfd);
  printf("catcher!");
  exit(0);
}

Serwer

#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#define SIZE sizeof(struct sockaddr_in)

int newsockfd;

void catcher(int signo);

int main() {
  int sockfd;
  char c;
  //struktura sygnalu doobsługi
  static struct sigaction act;
  act.sa_handler=catcher;
  sigfillset(&(act.sa_mask));
  sigaction(SIGPIPE, &act, NULL);
  //zainicjuj gniazdo internetowe z umuerem portu 7000 i adresem każdym(0.0.0.0), określonym jako INADDR_ANY
  struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY};
  //ustaw punk końcowy transportu - utwórz gniazdo
  if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("socket call failed");
    exit(1);
  }
  //zwiąż adres serwera z punktem końcowym(gniazdem)
  if(bind(sockfd, (struct sockaddr *)&server, SIZE) == -1)
  {
    perror("bind failed");
    exit(1);
  }
  //zacznij nasłuchiwać przychodzących połączeń
  if(listen(sockfd, 5) == -1)
  {
    perror("listen failed");
    exit(1);
  }
  
  for(;;)
  {
    //przyjmij połączenie
    if(newsockfd=accept(sockfd, NULL, NULL) == -1)
    {
      perror("accept failed");
      continue;
    }
    //utwórz potomka do pracy z połączeniem jeśli proces potomny wysyłaj i odbieraj informacje klienta
    if(fork() == 0)
    {
      //odbierz dane
      while(recv(newsockfd, &c, 1, 0) > 0)
      {
	//zmień na wielki litery i odeślij z powrotem
	c=toupper(c);
	printf("Recived %c, send %c\n", tolower(c), c);
	send(newsockfd, &c, 1, 0);
      }
      //gdy klient nie wysyła dlużej informacji gniazdo może byc zamknięte i proces potomny zakończony
      close(newsockfd);
      exit(0);
    }
    //rodzic nie potrzebuje newsockfd
    close(newsockfd);
  }
}

void catcher(int signo)
{
  close(newsockfd);
  printf("close");
  exit(0);
}
0

INADDR_ANY wcale nie oznacza "każdego adresu". Oznacza dowolny INTERFEJS. Bindować z adresem musisz mimo wszystko.

0

Zmieniłem fragment kodu z serwera tak żeby bindować gniazdo z adresem
Serwer

  //zainicjuj gniazdo internetowe z umuerem portu 7000 i adresem każdym(0.0.0.0), określonym jako INADDR_ANY
  struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY};
  server.sin_addr.s_addr= inet_addr("10.43.12.6");

I teraz serwer przyjmuje dopiero 2 połączenie ... tzn. pierwszy klient nie może się połączyć, dopiero drugi komunikuje się poprawnie z serwerem.

0

Puść to w takim razie pod debuggerem i zobacz gdzie się pojawia problem.

0

Dla serwera wystarczy INADDR_ANY o ile nie mamy kilku kart sieciowych na tym samym komputerze. A nawet jak jest kilka to też wystarczy INADDR_ANY z tym że wtedy nie da się przewidzieć na jakim IP będzie ten serwer.

Co do problemu to jest tu:
//rodzic nie potrzebuje newsockfd
close(newsockfd);
Owszem rodzić nie potrzebuje, ale to nie znaczy że ma zamykać połączenie. Po zamknięciu odcinasz połączenie z klientem.

0

INADDR_ANY wcale nie oznacza "każdego adresu". Oznacza dowolny INTERFEJS. Bindować z adresem musisz mimo wszystko.

ip(7) - Linux man page napisał(a)

When INADDR_ANY is specified in the bind call the socket will be bound to all local interfaces.

Adres jest nieistotny. Będzie działać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1