Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Создадим консольное приложение


Автор: Sergio 21.1.2007, 00:29
Здраствуйте. Хочу продолжить тему по ТСП протоколу. Вот моя функция которая создаёт сокет:

Код
WSADATA wsa;                                                // Info about winsock
    WSAStartup(MAKEWORD(1,0), &wsa);                           
    SOCKET mySocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 

     sockaddr_in AdressInfo;
     AdressInfo.sin_family = AF_INET;
     AdressInfo.sin_port = 4888;
     AdressInfo.sin_addr.s_addr=htonl(INADDR_ANY);

     bind(mySocket, (SOCKADDR*)&AdressInfo), sizeof(AdressInfo);


Что то с биндом не так.. smile 
error C2660: 'bind' : function does not take 2 arguments 

Спасибо.
P.S.  htonl(INADDR_ANY)   что это? smile 

Автор: nworm 21.1.2007, 00:52
Цитата(Sergio @ 21.1.2007,  00:29)
Код

     bind(mySocket, (SOCKADDR*)&AdressInfo), sizeof(AdressInfo);


Что то с биндом не так.. smile 
error C2660: 'bind' : function does not take 2 arguments 

 smile  Скобка после AdressInfo явно лишняя.

Автор: Romikgy 21.1.2007, 01:00
Цитата(Sergio @  20.1.2007,  23:29 Найти цитируемый пост)
htonl(INADDR_ANY)   что это?

любой адрес, так и написано smile

Автор: nworm 21.1.2007, 01:16
http://www.kstu.kz/~tolik/info/Glibc/glibc-11.html

Автор: Sergio 21.1.2007, 01:28
nworm, вот написал так:
Код
bind(mySocket, (SOCKADDR*)&AdressInfo, sizeof(AdressInfo);


Ошибка: error C2143: syntax error : missing ')' before ';'

Автор: nworm 21.1.2007, 01:32
пробый так
Код

 bind(mySocket, (SOCKADDR*)&AdressInfo, sizeof(AdressInfo));

Автор: SparF 21.1.2007, 01:37
ну так он тебе и написал:
"Поставь, пожалуйста, скобку перед ;" )))

Автор: Sergio 21.1.2007, 02:27
 Хотел проверить возращаемые ошибки Вызвал две "прослушки" сразу но они вернули два нуля. Почему? А должно ведь вернуть ноль и значение ошибки.


Код
cout<<listen(mySocket, 5);
     cout<<listen(mySocket, 10);



Автор: SparF 21.1.2007, 03:37
Sergio, а почему обязательно ошибку?
вот, что в http://www.hmug.org/man/2/listen.php сказано
Цитата

     Listen() will fail if:

     [EBADF]            The argument s is not a valid descriptor.

     [ENOTSOCK]         The argument s is not a socket.

     [EOPNOTSUPP]       The socket is not of a type that supports the opera-
                        tion listen().


Автор: Sergio 21.1.2007, 04:15
Есть ещё такое возращение:

Код
WSAEISCONN — сокет уже подключен.


Автор: SparF 21.1.2007, 09:24
сейчас посмотрим

Автор: SparF 21.1.2007, 10:31
Sergio, а ты под какую ОС пишешь? Я про то, что в мсдн нашел про WSAEISCONN =)
а потом решил покопаться в Линухе на эту тему, результаты меня не только откровенно порадовали, но еще и удивили  :hehe - зацепило))
1. в Линухе как факт отсутствует ошибка WSAEISCONN, а есть EISCONN
2. EISCONN вызывается в случае:
для функции connect:
Код

1244    if (sock->state != SS_UNCONNECTED)
1245            return -EISCONN;

аналогично для  send_msg:
Код

468                 if (sock->state != SS_UNCONNECTED)
469                         return -EISCONN;

И других вариантов встретить его в socket.c нет  :p 
3. сам же код ошибки  (Linux/include/asm-generic/errno.h)
Код

79 #define EISCONN         106     /* Transport endpoint is already connected */

4. Что же касается работы конкретно функции listen то вызывается одна из asmlinkage long sys_socketcall(Linux/net/socket.c), как и полностью все функции работы с сокетами вот кусок кода (нас интересуют возвращаемые ошибки)
Код

1970 asmlinkage long sys_socketcall(int call, unsigned long __user *args)
1971 {
...
1976         if(call<1||call>SYS_RECVMSG)
1977                 return -EINVAL;
1978 
1979         /* copy_from_user should be SMP safe. */
1980         if (copy_from_user(a, args, nargs[call]))
1981                 return -EFAULT;
1982 
1983         err = audit_socketcall(nargs[call]/sizeof(unsigned long), a);
1984         if (err)
1985                 return err;
...
1990         switch(call) 
1991         {
...
2001                 case SYS_LISTEN:
2002                         err = sys_listen(a0,a1);
2003                         break;
...
2048         }
2049         return err;
2050 }

по возможным ошибкам:
(include/asm-generic/errno-base.h)
Код

17 #define EFAULT          14      /* Bad address */
...
25 #define EINVAL          22      /* Invalid argument */

с первой ошибкой тут все ясно(первая - в порядке проверки, а не объявления в errno-base.h))
вторая же возникает если некорректно отрабатывает копирование блока данных из пространства пользователя (тоже вряд ли имеет отношение к нашему вопросу )))

если смотреть дальше по коду(Linux/kernel/auditsc.c), то единсвенное, что может вернуть audit_socketcall это
Код

15 #define ENOMEM          12      /* Out of memory */

значит нам опять же не сюда)))
остается только одна функция, которая как-то может повлиять на ошибку: sys_listen (net/socket.c, line 1362)
она совсем маленькая:
Код

1360 int sysctl_somaxconn = SOMAXCONN;
1361 
1362 asmlinkage long sys_listen(int fd, int backlog)
1363 {
1364         struct socket *sock;
1365         int err, fput_needed;
1366         
1367         if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
1368                 if ((unsigned) backlog > sysctl_somaxconn)
1369                         backlog = sysctl_somaxconn;
1370 
1371                 err = security_socket_listen(sock, backlog);
1372                 if (!err)
1373                         err = sock->ops->listen(sock, backlog);
1374 
1375                 fput_light(sock->file, fput_needed);
1376         }
1377         return err;
1378 }

тут только два варианта, откуда может появиться ошибка
первый: security_socket_listen (include/linux/security.h, line 2703)
Код

715  * @socket_listen:
716  *      Check permission before socket protocol layer listen operation.
717  *      @sock contains the socket structure.
718  *      @backlog contains the maximum length for the pending connection queue.
719  *      Return 0 if permission is granted.

по комменту понятно - проверяет права на доступ (опять же - похоже, что "не та степь" по отношению к нашему вопросу)
второй:
(net/tipc/socket.c, line 1299):
Код

1299 static int listen(struct socket *sock, int len)
1300 {
1301         /* REQUIRES SOCKET LOCKING OF SOME SORT? */
1302 
1303         if (sock->state == SS_READY)
1304                 return -EOPNOTSUPP;
1305         if (sock->state != SS_UNCONNECTED)
1306                 return -EINVAL;
1307         sock->state = SS_LISTENING;
1308         return 0;
1309 }

как видишь она может вернуть только две ошибки (include/asm-generic/errno.h, line 68):
Код

68 #define EOPNOTSUPP      95      /* Operation not supported on transport endpoint */

это была первая, EINVAL описана выше.
при этом первая вызывается если sock->state== (Linux/net/tipc/socket.c):
Код

59 #define SS_READY        -2      /* socket is connectionless */

по комменту ясно, что это "если сокет (в силу каких-то причин) не может быть подключен"
а вторая если sock->state!= (Linux/include/linux/net.h)
Код

51         SS_UNCONNECTED,                 /* unconnected to any socket    */

опять же по комменту видно, что если сокет уже к чему-то подключен

Коды ошибок, указанных мной ранее из мана в коде listen я так и не нашел - люди, не судите строго  :rolleyes
Так что, имхо, не все так просто, как хотелось бы, но и усложнять лишний раз не надо. 
Думаю, что этого достаточно, чтобы понять: в зависимости от ОС реализация вроде бы "стандартных" функций может меняться))) как же это сделано в винде - а хз)) не знаю (

PS http://lxr.linux.no/ однозначно рулит  :inlove 
ковырялся в исходниках 2.6.17.13 
гы...прикольно :happy 


Цитата(Sergio @  21.1.2007,  02:27 Найти цитируемый пост)
 Хотел проверить возращаемые ошибки Вызвал две "прослушки" сразу но они вернули два нуля. Почему? А должно ведь вернуть ноль и значение ошибки.

Так что забей ))) исходить надо из того, что есть
если же пишешь под винду - то тайна остается покрыта мраком :( тут надо спрашивать у продвинутых виндузойдов, коим я не являюсь  :(
А, вот еще - на опытных прогах я все это не проверял, возможно, что в реальности еще что-то накладывается.

Автор: drZmeu 21.1.2007, 10:53
Народ да посоветуйте ему книжку какую нить... 
Sergio -> С++ Глазами хакера... В нете скачай примерный вес 3 мегобайта... Там много чего про сокеты и т.д
Удачи тебе. 

Автор: SparF 21.1.2007, 10:58
мда....а то я что-то размахнулся....
вот ссылка, которая меня ну очень в свое время порадовала (вообще класс!)
http://beej.us/guide/bgnet/

Автор: Sergio 21.1.2007, 17:47
 Почитал я книгу. И вот что у меня получилось (не очень получилось smile ) . Самый примитивный сервер. Подскажите может что-то не неправильно, тогда подкоректируйте. Он даже не выводит буфер.Только принимает.

Код
using namespace std;
    WSADATA wsa;                                                // Info about winsock2
    char    szRecvBuff[1024];

    WSAStartup(MAKEWORD(1,0), &wsa);                            // Loading library winsock2
    SOCKET mySocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    // Создание сокета
      

     sockaddr_in AdressInfo;
     AdressInfo.sin_family = AF_INET;                           // Internet technology (TCP,UDP etc)
     AdressInfo.sin_port = htons(4888);
     AdressInfo.sin_addr.s_addr=htonl(INADDR_ANY);

     bind(mySocket, (SOCKADDR*)&AdressInfo, sizeof(AdressInfo));  //Связывание даных с сокетом
     
     listen(mySocket, 5);                                         // Прослушка

     int AdressInfoSize = sizeof(AdressInfo);

     while(1) {
    
         accept(mySocket,(SOCKADDR*)&AdressInfo,&AdressInfoSize);
          cout<<recv(mySocket, szRecvBuff, 1024, 0);     
     }    

Простите за нечитабельность(писал в 4 утра).

SparF, я пишу под виндовс.

P.S. Подскажите где в структуре sockaddr_in указывается IP. Спасибо зарание.

Автор: SparF 21.1.2007, 18:05
Sergio, доки читать надо  smile 
Цитата

     The call returns -1 on error.  If it succeeds, it returns a non-negative
     integer that is a descriptor for the accepted socket.

иначе говоря accept возвращает сокет с которого нужно осуществлять чтение
Код

        if ((new_fd = accept(mySocket, (struct sockaddr *)&their_addr,
                                                       &sin_size)) == -1) {
            perror("accept");
            continue;
        }

кроме этого - если ты оставишь все как есть, то accept перепишет твою AdressInfo информацией об удаленном клиенте -- туда пишутся данные об удаленной машине

Мой тебе совет, досконально изучи
http://beej.us/guide/bgnet/output/html/clientserver.html#simpleserver

Добавлено @ 18:14 
И не пиши код, до тех пор пока ты не знаешь что означает каждый символ из примитивного примера и как этот пример работает.

Автор: Sergio 21.1.2007, 19:02
Прочитал я в доках, что после виполнения функции  accept(mySocket, (struct sockaddr *)&their_addr,    &sin_size)), сервер сохраняет адрес клиента в структуре their_addr. Помогите найти где именно... А то я не нашёл. Спасибо.
Думал что здесь (their_addr.sin_addr.s_addr) но выводить какоё-то непонятное число smile 



Автор: ptr 22.1.2007, 07:55
Цитата(Sergio @  21.1.2007,  05:27 Найти цитируемый пост)
Хотел проверить возращаемые ошибки Вызвал две "прослушки" сразу но они вернули два нуля. Почему? А должно ведь вернуть ноль и значение ошибки.

Показывай весь код.

Цитата(SparF @  21.1.2007,  21:05 Найти цитируемый пост)
Sergio, доки читать надо   Цитата     The call returns -1 on error.  If it succeeds, it returns a non-negative     integer that is a descriptor for the accepted socket.иначе говоря accept возвращает сокет с которого нужно осуществлять чтение

SparF, не надо смешивать Windows и *nix. В Windows, например, accept возвращает INVALID_SOCKET.

Цитата(Sergio @  21.1.2007,  22:02 Найти цитируемый пост)
сервер сохраняет адрес клиента в структуре their_addr.

Код

inet_ntoa(their_addr.sin_addr)

Автор: Sergio 27.1.2007, 00:39
Возникла проблема. Как передать структуру? Тоесть я хочу передать пакет где будет:
имя  клиента
сообщение
Ip клиента

Сначала думал это всё запихать в массив чаров и передавать, но потом передумал, так как надо ставить какие-то ограждения(для сортировки на сервере): (/сообщение/имя  клиента/Ip клиента/) а я не хочу ограничивать пользователя какими-то символами. Что мне делать? Как мне быть? smile 

Автор: Romikgy 27.1.2007, 01:04
Цитата(Sergio @  26.1.2007,  23:39 Найти цитируемый пост)
Как передать структуру? 

по сети?
тогда 
Цитата(Sergio @  26.1.2007,  23:39 Найти цитируемый пост)
всё запихать в массив чаров и передавать


Цитата(Sergio @  26.1.2007,  23:39 Найти цитируемый пост)
Что мне делать? Как мне быть?

длины строк передавай (кол-во букф)

Автор: witex 27.1.2007, 05:31
привельно Ромик говорит! Структуру передаёшь через массив чаров, а принимающая сторона опять её превращает в структуру, вот и всё!
Код

send(my_sock,(const char*)mystruct,syzeof(ьныекгсе),0);

Так и файлы передаются и всё подрят! Сам вначале парился! Но тут на форуме и решили проблему!

Автор: Sergio 30.1.2007, 00:46
Вот что я написал:
Код

struct _paket {
      char msg[50] = {"Hello world!"};
      int user = 10;
  };

_paket paket;

Потом:
Код

 send(mySocket,(char*)&paket,sizeof(paket),0); 

Какая-то ошибка smile 
И еще вопрос: как принимать структуру? Что чему присваивать?

Автор: witex 31.1.2007, 02:37
Код

send(mySocket,(const char*)&paket,sizeof(paket),0); 

выше же написал!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)