LINUX.ORG.RU

Сокеты.


0

0

Хочу написать клиент и сервер. Сервер посылает 256 символов S, а клиент их пишет. Но порт даже не открывается.


server.c:


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <memory.h>


main () {
int s, s_new;
int from_len;
struct sockaddr_in sin, from_sin;

s = socket (AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 5020;
bind (s, (struct sockaddr *)&sin, sizeof(sin));
listen (s, 3);

from_len = sizeof(from_sin);
s_new = accept (s, &from_sin, &from_len);
int i;
for(i=0;i<256;i++)
send(s_new,"S",1,0);
shutdown (s_new, 0);
close (s_new);
}

★★

> s = socket (AF_INET, SOCK_STREAM, 0)

- Доктор, мне кажется, я дурак... - Успокойтесь, пациент, вам НЕ кажется!

Так вот это я к чему? А к тому, что надо читать man socket, man socket, и снова man socket, и твердо усвоить, что все параметры введены не зря.

А в твоем примере 0 в третьем параметре при вызове socket() означает IPPROTO_IP, что влечет необходимость SOCK_RAW во втором параметре и работоспособность только из-под root'а.

Но по твоему коду видно, что тебе нужен TCP, поэтому делай-ка ты для начала s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)

Затем: говорить s.sin_port = 5020, конечно, тоже круто... Если у тебя архитектура x86, и задача должна забиндиться на порт 39955.

Так что еще раз RTFM.

И вообще TFM рулит.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

>>А в твоем примере 0 в третьем параметре при 
>>вызове socket() означает IPPROTO_IP, что 
>>влечет необходимость SOCK_RAW во втором 
>>параметре и работоспособность только из-под root'а. 

это глупость.

А остальное правильно говоришь.

anonymous
()
Ответ на: комментарий от anonymous

>>А в твоем примере 0 в третьем параметре при
>>вызове socket() означает IPPROTO_IP, что
>>влечет необходимость SOCK_RAW во втором
>>параметре и работоспособность только из-под root'а.
>
> это глупость.

Нет. Смотреть cd /usr/include, grep -R IPPROTO_ *

Есть константа IPPROTO_IP. Вполне даже рабочая, и требующая типа сокета SOCK_RAW, причем этот тип сокета создается и связывается только при наличии пермишнов соответствующих (в простейшем случае euid==0). См. исходники teardrop, там был пример :-)

Почему 39955?

Берем число 5020, приводим его к u_int16_t (==WORD). В man сказано, что sin_port должен быть в network byte order, т.е. сначала старший байт, потом младший. На x86 порядок байтов другой -- сначала младший, потом старший. Соответственно, переставляя байты получаем 39955.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

Спасибо. Не мог бы ты написать, как программа будет выглядеть, а то всё равно порт не открывается.

drish ★★
() автор топика
Ответ на: комментарий от drish

Работающий вариант:

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

#define PORT 2048

main () {
  int i;
  struct sockaddr_in local, remote;
  int serv, client;
  int temp;

  serv = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
  memset(&local,0,sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = (PORT % 256)*256 + PORT/256;
  bind (serv, (struct sockaddr *)&local, sizeof(local));
  listen (serv, 3);

  temp = sizeof(remote);
  client = accept (serv, (struct sockaddr *)&remote, &temp);
  for(i=0;i<256;i++) {
    send(client,"S",1,0);
  }
  shutdown( client, 0 );
  close( serv );
  //
  // а вот это уже не нужно
  //
  // close (s_new);
  return 0;
}

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

2no-dashi:

Действительно, сокет создается только из-под рута.
Но именно обычный tcp сокет. (Red Hat 9)
Тем не менее, приношу извинения за "глупость".

anonymous
()
Ответ на: комментарий от no-dashi

MAN SOCKET

NAME
       socket - create an endpoint for communication

SYNOPSIS
       #include <sys/types.h>
       #include <sys/socket.h>

       int socket(int domain, int type, int protocol);

...


The  protocol  specifies  a  particular  protocol  to  be used with
the socket.  Normally only a single protocol exists to support a
particular socket  type  within  a given protocol family, in which
a case protocol can be specified as 0

...


Таким образом, 0 в поле protocol является допустимым 
значением для SOCK_STREAM.

anonymous
()
Ответ на: комментарий от anonymous

>Действительно, сокет создается только из-под рута.

это уже я прогнал.

Итого - можно смело использовать protocol=0 в функции socket().
Даже для TCP ;)

anonymous
()
Ответ на: комментарий от anonymous

> Итого - можно смело использовать protocol=0 в функции socket(). Даже для TCP ;)

ЕСЛИ у тебя нет поддержки других потоковых протоколов указанного семейства. А так действительно, 0 в некоторых случаях прокатывает :-)

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

чего спорить, смотрим net/ipv4/af_inet.c:inet_create()

для socket(AF_INET, SOCK_{STREAM,DGRAM}, 0)

if (IPPROTO_IP == protocol) { // то есть 0
protocol = answer->protocol;
break;
}

для любого type в семействе PF_INET.

так что socket(AF_INET, SOCK_{STREAM,DGRAM}, 0)
выставит protocol = SOCK_{STREAM,DGRAM}.

idle ★★★★★
()
Ответ на: комментарий от idle

> выставит protocol = SOCK_{STREAM,DGRAM}.

Описка :)

выставит protocol = IPPROTO_{TCP,UDP}

idle ★★★★★
()
Ответ на: комментарий от no-dashi

И из-под рута порт не открывается. nmap'ом себя сканирую, порта этого нет. Даже отдельно (-p '2048').

drish ★★
() автор топика
Ответ на: комментарий от drish

> И из-под рута порт не открывается. nmap'ом себя сканирую, порта этого нет. Даже отдельно (-p '2048')

Да все открывается. Самолично проверил.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

Работает :). И из-под юзера, и из-под рута.

drish ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.