Перейти к содержанию
    

Пишу на vxWorks но наверно это не важно. Принцип везде одинаков.

Создаю сокет и пытаюсь подключиться к серверу. Сервером выступает компьютер.

На компьютере запускаю Hercules -> TCP Server -> Port 8200 (SERVER_PORT_NUM) -> Listen. Сервер бежит.

 

На стороне прибора

STATUS TCP_ClientConnect (char *serverName, int *soc_desc) 
{ 
    struct sockaddr_in  serverAddr;    /* server's socket address */ 
    int                 sockAddrSize;  /* size of socket address structure */ 
    int                 sFd;           /* socket file descriptor */ 

    /* create client's socket */ 
    if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) 
    { 
        //perror ("socket"); 
        printf ("SOCKET ERROR\n");
        return (ERROR); 
    } 

    /* bind not required - port number is dynamic */ 
    /* build server socket address */ 
    sockAddrSize = sizeof (struct sockaddr_in); 
    bzero ((char *) &serverAddr, sockAddrSize); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_len = (u_char) sockAddrSize; 
    serverAddr.sin_port = htons (SERVER_PORT_NUM); 

    if (((int)(serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && 
        ((int)(serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) 
    { 
        printf ("UNKNOWN SERVER NAME\n");
        close (sFd); 
        return (ERROR); 
    } 
    
    /* bind a port number to the socket */
    if (bind(sFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == ERROR)
    {
        printf("BIND ERROR\n");
        return (ERROR); 
    }

    /* connect to server */ 
    if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) 
    { 
        printf ("CONNECTION ERROR\n");
        close (sFd); 
        return (ERROR); 
    } 
    
    *soc_desc = sFd;
    
    return (OK); 
}

И запускаю таск

int socket_descriptor=0;
char *server_ip = "10.0.0.80";

void tSpectraTaskEntryPoint()
{
    
    if (TCP_ClientConnect(server_ip, &socket_descriptor)==ERROR)
     printf ("CLIENT CONNECT ERROR\n");
    else
    printf("CLIENT CONNECT OK descriptor = %d\n", socket_descriptor);
    
   SpectraMain();
}

Получаю ошибку

BIND ERROR

CLIENT CONNECT ERROR

Значит не выполняется привязка сокета к серверу? Я что то не так делаю?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

модифицировал функцию чтоб выводить информацию.

STATUS TCP_ClientConnect (char *serverName, int *soc_desc) 
{ 
    struct sockaddr_in  serverAddr;    /* server's socket address */ 
    int                 sockAddrSize;  /* size of socket address structure */ 
    int                 sFd;           /* socket file descriptor */ 

    /* create client's socket */ 
    if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) 
    { 
        printf ("SOCKET ERROR\n");
        return (ERROR); 
    } 
    else
         printf ("SOCKET DESC = %d\n", sFd);

    /* bind not required - port number is dynamic */ 
    /* build server socket address */ 
    sockAddrSize = sizeof (struct sockaddr_in); 
    bzero ((char *) &serverAddr, sockAddrSize); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_len = (u_char) sockAddrSize; 
    serverAddr.sin_port = htons (SERVER_PORT_NUM); 

    if (((int)(serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && 
        ((int)(serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) 
    { 
        printf ("UNKNOWN SERVER NAME\n");
        close (sFd); 
        return (ERROR); 
    } 
    else
    {
        printf ("ADDR = %d\n", serverAddr.sin_addr.s_addr);
        printf ("PORT = %d\n", serverAddr.sin_port);
        
    }
    
    /* bind a port number to the socket */
    if (bind(sFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == ERROR)
    {
        printf("BIND ERROR\n");
        return (ERROR); 
    }


    /* connect to server */ 
    if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) 
    { 
        printf ("CONNECTION ERROR\n");
        close (sFd); 
        return (ERROR); 
    } 
    
    *soc_desc = sFd;
    
    return (OK); 
}

вижу

SOCKET DESC = 26

ADDR = 1342177290

PORT = 2080

BIND ERROR

CLIENT CONNECT ERROR

 

перевожу 1342177290 в ИП аддресс получается 80.0.0.10 - перевернутый. порт тоже - вместо 8200 - 2080.

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

перевожу 1342177290 в ИП аддресс получается 80.0.0.10 - перевернутый. порт тоже - вместо 8200 - 2080.

 

И какой вывод можно получить?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Клиентский сокет можно не bind-ить, так как порт выделяется динамически, у вас же это и написано в комментариях.

bind на клиенте нужен, если вы хотите привязать сокет к конкретному локальному интерфейсу и порту.

У вас же идет bind к удаленному адресу и порту, что, конечно же, ни в какие ворота...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Клиентский сокет можно не bind-ить, так как порт выделяется динамически, у вас же это и написано в комментариях.

bind на клиенте нужен, если вы хотите привязать сокет к конкретному локальному интерфейсу и порту.

У вас же идет bind к удаленному адресу и порту, что, конечно же, ни в какие ворота...

но я хочу чтоб сокет обращался к серверу по его IP - 10.0.0.80 И порту 8200. Я не должен указать сокету куда обращаться? Это какой то бродкаст получается.

 

убрал байндинг и заработало.

проверяю

void SpectraMain()
{
    while (spectra_alive)
    {
        if (TCP_ClientRead(read_buf, socket_descriptor) != ERROR)
        {
            printf ("CLIENT RECIEVED MESSAGE\n");
            //echo back
            TCP_ClientWrite(read_buf, socket_descriptor);
        }
        else
        {
            TCP_ClientWrite("no message", socket_descriptor);
        }
            
        taskDelay(50);
    }
}

на Hercules -> TCP Server посылаю строку - получаю CLIENT RECIEVED MESSAGE + строку.

спасибо.

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но я хочу чтоб сокет обращался к серверу по его IP - 10.0.0.80 И порту 8200. Я не должен указать сокету куда обращаться? Это какой то бродкаст получается.

В это невозможно поверить, но для этого есть функция connect() :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут возникает такой вопрос. Если связь с сервером прервалась? Что делать? Периодически проверять связь с сервером? А сокет? Он жив пока его не закрыли? Или надо проверять и его?

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все надо проверять. Здесь я намучился с этими чертовыми сокетами! Сокет - не файл, запись в закрытый с другой стороны сокет никаких ошибок не даст! Поэтому нужно вводить таймауты и/или периодические рукопожатия.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все надо проверять. Здесь я намучился с этими чертовыми сокетами! Сокет - не файл, запись в закрытый с другой стороны сокет никаких ошибок не даст! Поэтому нужно вводить таймауты и/или периодические рукопожатия.

я понял. а как проверять? периодически делать if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) или можно как то более красиво?

а сокет как проверить? if (socket_descriptor != 0) ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все уже придумано за нас. Почитайте про SO_KEEPALIVE. Там по умолчанию довольно большие таймауты, но вы можете установить свои.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все уже придумано за нас. Почитайте про SO_KEEPALIVE. Там по умолчанию довольно большие таймауты, но вы можете установить свои.

нашел такой пример

/* Set the option active */
   optval = 1;
   optlen = sizeof(optval);
   if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
      perror("setsockopt()");
      close(s);
      exit(EXIT_FAILURE);
   }
   printf("SO_KEEPALIVE set on socket\n");

это чтоб включить SO_KEEPALIVE. компилируется без ошибок.

а как теперь проверить жив сокет или нет?

 

я так понимаю с выставленной опцией где то бежит проверка каждые tcp_keepalive_intvl и наверно выставляется флаг гдето в статусном регистре, который надо проверять.

 

The SO_KEEPALIVE option causes a packet (called a 'keepalive probe')

to be sent to the remote system if a long time (by default, more than

2 hours) passes with no other data being sent or received. This packet

is designed to provoke an ACK response from the peer. This enables

detection of a peer which has become unreachable (e.g. powered off or

disconnected from the net).

а где я вижу этот ACK response from the peer?

 

Все надо проверять. Здесь я намучился с этими чертовыми сокетами! Сокет - не файл, запись в закрытый с другой стороны сокет никаких ошибок не даст! Поэтому нужно вводить таймауты и/или периодические рукопожатия.

у меня этот код компилируется.

static int waittoread(int sock){
    fd_set fds, efds;
    struct timeval timeout;
    int rc;
    timeout.tv_sec = 1; // wait not more than 1 second
    timeout.tv_usec = 0;
    FD_ZERO(&fds);
    FD_ZERO(&efds);
    FD_SET(sock, &fds);
    FD_SET(sock, &efds);
    do{
        rc = select(sock+1, &fds, NULL, &efds, &timeout);
        if(rc < 0){
            if(errno != EINTR){
                putlog("Server not available");
                WARN("select()");
                return -1;
            }
            continue;
        }
        break;
    }while(1);
    if(FD_ISSET(sock, &efds)) return -1; // exception - socket closed
    if(FD_ISSET(sock, &fds))  return  1;
    return 0;
}

это значит так можно проверить и сервер и сокет?

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а как теперь проверить жив сокет или нет?
Он закроется, а дальше write() и read() будут возвращать ноль - это и будет признаком того, что соединение разорвано. Кажется так.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Он закроется, а дальше write() и read() будут возвращать ноль - это и будет признаком того, что соединение разорвано. Кажется так.

допустим сервер не посылает мне ничего но соединение живо. в read() я получу 0 но это может быть потому что сервер ничего не послал.

я думаю есть какие то статусные биты которые говорят что соединение разорвано.

делаю так

 #if KEEPALIVE_ON
    /* Set the option active */
    optval = 1;
    optlen = sizeof(optval);
    if(setsockopt(sFd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0)
    {
        close(sFd);
        return (ERROR); 
    }
    printf("SO_KEEPALIVE set on socket\n");
    
    /* Interval (in seconds) between keepalives */
    optval = 1; 
    setsockopt(sFd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen);
    /* Maximum number of keepalives before dropping the connection */
    optval = 10;
    setsockopt(sFd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen);
    /* Send first keepalive probe when the connections been idle this time (in seconds) */
    optval = 5;
    setsockopt(sFd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen);
    #endif

теперь по идее мы должны иметь какую то индикацию, статус соединения.

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если удаленный сервер корректно закрыл TCP-соединение, то на стороне клиента попытка записи-чтения должна возвращать ошибку "Bad file descriptor" или что-то в этом духе. Хотя зависит от реализации стека, вероятно.

Гораздо сложнее история, если разрыв соединения произошел внезапно и физически (выдернули кабель). Тут или мудрить с keep-alive, или самостоятельно реализовывать логику закрытия сокета при неполучении ответа от сервера в то или иное время.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если удаленный сервер корректно закрыл TCP-соединение, то на стороне клиента попытка записи-чтения должна возвращать ошибку "Bad file descriptor" или что-то в этом духе. Хотя зависит от реализации стека, вероятно.

Гораздо сложнее история, если разрыв соединения произошел внезапно и физически (выдернули кабель). Тут или мудрить с keep-alive, или самостоятельно реализовывать логику закрытия сокета при неполучении ответа от сервера в то или иное время.

а код от Эдди

static int waittoread(int sock){
    fd_set fds, efds;
    struct timeval timeout;
    int rc;
    timeout.tv_sec = 1; // wait not more than 1 second
    timeout.tv_usec = 0;
    FD_ZERO(&fds);
    FD_ZERO(&efds);
    FD_SET(sock, &fds);
    FD_SET(sock, &efds);

     rc = select(sock+1, &fds, NULL, &efds, &timeout);
        if(rc < 0)
        {
                putlog("Server not available");
                return -1;
        }
        break;

    if(FD_ISSET(sock, &efds)) return -1; // exception - socket closed
    if(FD_ISSET(sock, &fds))  return  1;
    return 0;
}

разве он не проверяет все случаи? там и сервер и сокет проверяется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...