Netinet in h windows

Порт сокетных приложений из Unix в Windows

Как известно, концепция сокетов была разработана в Беркли, и затем реализована сначала в BSD, затем в Linux и, наконец, с некоторыми изменениями, и в Windows. Таким образом, это делает сетевое программирование на обеих платформах очень сильно похожим и перенос Unix приложения на Win-платформу становится не очень сложным делом.

Эта статья — попытка помочь тем, кто впервые решил осуществить порт сокетного приложения из Unix (Linux, BSD) в Windows. Зачем? Кто-то решает поднять свой уровень кодинга на новую высоту, кому-то это просто интересно, а кто-то ищет новые задачи для решения. Совет: не пытайтесь сразу портировать что-нибудь достаточно большое и сложное, начните с простых утилит вроде traceroute, nslookup и с прочтения этой статьи :-). Базовых знаний приемов сетевого программирования на C++ будет вполне достаточно. Все примеры из статьи компилировались на VC++ 6.0 под Win2k prof. и WinXP prof.

UNIX и Windows по разному обращаются с сокетами: в UNIX сокеты обрабатываются системой точно так же, как дескрипторы файлов integer типа, в то время как Windows это хэндл unsigned типа — SOCKET. В Unix все I/O действия выполняются чтением или записью в соответствующий дескриптор — число (integer) ассоциированное с открытым файлом, сетевым соединением, терминалом и т.п.

В Unix коды ошибок доступны через переменную errno, в Windows нужно использовать функцию WSAGetLastError().

И в Unix и в Windows порт определяется параметром, переданном функции htons(), но в Windows некоторые, наиболее часто используемые порты предопределены в
winsock.h:

IPPORT_ECHO — 7
IPPORT_DISCARD — 9
IPPORT_SYSTAT — 11
IPPORT_DAYTIME — 13
IPPORT_NETSTAT — 15
IPPORT_FTP — 21
IPPORT_TELNET — 23
IPPORT_SMTP — 25
IPPORT_TIMESERVER — 37
IPPORT_NAMESERVER — 42
IPPORT_WHOIS — 43
IPPORT_MTP — 57

Заголовочные файлы
Вот список функций Unix и соответствующих им .h-файлов

socket()
[ #include ]
[ #include ]

bind()
[ #include ]
[ #include ]

connect()
[ #include ]
[ #include ]

listen()
[ #include ]
[ #include ]

Эти два файла к сокетам не относятся, но обычно присутствуют в Unix программах:

Т.е. типичное начало сетевой UNIX программы выглядит так:

#include
#include
#include
#include
#include

При переносе в Windows, все эти строки заменяются на одну:

Объявление winsock.h уже включено в windows.h.

Вторым шагом будет линковка приложению Wsock32.lib (Для VC++: меню Project->Settings, на вкладке Link, дописать wsock32.lib к списку библиотек).

UNIX и Windows имеют ряд общих, выполняющих одинаковые функций
процедур. Это большинство функций работы с TCP/UDP, все функции преобразования + используемые ими структуры. Это, например, функции htons() и inet_addr() и структуры sockaddr и sockaddr_in.

Вот список этих функций:
socket()
bind()
listen()
connect()
accept()
sendto()
recvfrom()
gethostname()

А вот список функций, делающих одно и то же, различающихся только названиями:

Unix Windows
close() closesocket()
ioctl() ioctlsocket()
read() recv()
write() send()

Дополнительно к вышесказанному, каждое сокетное приложение Windows должно содержать вызовы функций WSASStartup() и WSACleanup(), которые подготавливают к использованию Winsock и освобождают его, соответственно.

Для начала, перенесем что-нибудь простенькое. Например утилиту, определяющую IP-адрес хоста по его имени. Вот UNIX код:

#include
#include /* Этот файл нужен функции
gethostbyname() */
#include
#include
#include

Читайте также:  Самый лучший firefox для windows

int main(int argc, char *argv[])
<
struct hostent *he;

if ((he=gethostbyname(argv[1]))==NULL)
<
printf («gethostbyname() error\n»);
exit (-1);
>

printf («Hostname : %s\n»,he->h_name); /* Вывод имени хоста */
printf («IP Address: %s\n»,inet_ntoa(*((struct in_addr *)he->h_addr))); /* И его IP-адреса
*/
>

Попытка скомпилировать этот код без изменений была горячо воспринята VC++ — компилятор ругнулся на отсутствие .h файлов и сообщил, что компилировать программу он не собирается :-). Первым делом удаляем 2-5 строки, заменив их на:

и немного изменим строку 6:

void main(int argc, char **argv)

не забыв прилинковать wsock32.lib к проекту. Теперь программа компилируется без проблем, но при попытке ею воспользоваться выдает лаконичное: «gethostbyname() error». В чем дело? Все просто, не были вызваны WSAStartup() и WSACleanup()! Добавляем вызовы этих функций и код нормально компилируется.

Вот код портированного, работающего Win приложения:

void main(int argc, char **argv)
<
WSADATA wsdata;
WSAStartup(0x0101,&wsdata);
struct hostent *he;

if (argc! = 2)
<
printf(«Usage: %s hostname\n»,argv[0]);
>

if ((he = gethostbyname(argv[1])) == NULL)
<
printf(«gethostbyname() error\n»);
>

printf («Hostname : %s\n»,he->h_name);
printf(«IP Address: %s\n»,inet_ntoa(*((struct in_addr *)he->h_addr)));

Конечно, это — очень простое приложение. Попробуем перенести программу посложнее
— TCP streaming server.

#include
#include
#include
#include

#define PORT 3550 /* Порт, открываемый программой */
#define BACKLOG 2 /* Число соединений */

main()
<
int fd, fd2; /* дескрипторы */
struct sockaddr_in server; /* информация о сервере */
struct sockaddr_in client; /* информация о клиенте */
int sin_size;

if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 )
< /* вызов socket() */
printf («socket() error\n»);
exit (-1);
>

server.sin_family = AF_INET;
server.sin_port = htons (PORT);
server.sin_addr.s_addr = INADDR_ANY;
bzero (&(server.sin_zero),8);

printf («You got a connection from %s\n», inet_ntoa(client.sin_addr) );
send (fd2,»Welcome to my server.\n»,22,0);
close (fd2);
>>

Итак, сначала повторим шаги из предыдущего примера — оставим объявления только windows.h и stdio.h и прилинкуем wsock32.lib. Попытка компиляции приносит две ошибки: одна — по поводу функции bzero(), вторая — по поводу функции
close() — компилятор сообщает, что она — invalid identifier :-). Первая ошибка лечится очень просто — удаляем всю 21-ю строку. Для исправления второй, смотрим в таблицу, приведенную выше и заменяем close() на ее Win-аналог — closesocket(). Добавляем вызовы WSAStartup() и WSACleanup() и voila — программа компилируется без проблем. После запуска программы видим пустую командную строку, все правильно — сервер ждет клиента :-).

Windows код сервера:

#include
#include
#define PORT 3550
#define BACKLOG 2

main()
<
WSADATA wsdata;
WSAStartup(0x0101,&wsdata);

struct sockaddr_in server;
struct sockaddr_in client;
int sin_size;

if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 )
<
printf(«socket() error\n»);
exit(-1);
>

server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;

if (listen (fd,BACKLOG) == -1)
<
printf («listen() error\n»);
exit (-1);
>

while (1)
<
sin_size=sizeof (struct sockaddr_in);

printf («You got a connection from %s\n»,inet_ntoa(client.sin_addr) );
send (fd2,»Welcome to my server.\n»,22,0);
closesocket (fd2);

TCP streaming client

#include
#include
#include
#include
#include /* необходим для struct hostent */

#define PORT 3550 /* Порт, к которому будем коннектиться */
#define MAXDATASIZE 100 /* Макс. размер данных в байтах */

int main (int argc, char *argv[])
<
int fd, numbytes; /* дескрипторы */
char buf[MAXDATASIZE]; /* здесь будем хранить полученный текст */

struct hostent *he;
struct sockaddr_in server;

Читайте также:  Winflash asus windows 10 64 bit что это

if ((he=gethostbyname(argv[1]))==NULL)
<
printf(«gethostbyname() error\n»);
exit(-1);
>

if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1)
<
printf(«socket() error\n»);
exit(-1);
>

server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(server.sin_zero),8);

if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1)
<
printf(«recv() error\n»);
exit(-1);
>
buf[numbytes]=’\0′;
printf(«Server Message: %s\n»,buf);
close(fd);
>

И, без лишних слов, Windows код — для его получения нужно проделать те же, вышеописанные, шаги.

#define PORT 3550
#define MAXDATASIZE 100

int main(int argc, char *argv[])
<
WSADATA wsdata;
WSAStartup(0x0101,&wsdata);
int fd, numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in server;

if ((he=gethostbyname(argv[1])) == NULL)
<
printf(«gethostbyname() error\n»);
exit(-1);
>

if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1)
<
printf(«socket() error\n»);
exit(-1);
>

server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *((struct in_addr *)he->h_addr);

if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1)
<
printf(«recv() error\n»);
exit(-1);
>

buf[numbytes] = ‘\0’;
printf(«Server Message: %s\n»,buf);
closesocket(fd);
WSACleanup();
return -1;
>

Запустив клиента (при запущенном сервере, естественно) с аргументом localhost (что-то вроде tcp_client.exe localhost) видим приветствие сервера — «Welcome to my server». С чем я тебя и поздравляю
:-).

Вот те шаги, которые нужно делать в первую очередь, при переносе приложений:

1. Заменить объявления заголовочных файлов UNIX на windows.h и прилинковать wsock32.lib
2. Добавить вызовы функций WSAStartup() и WSACleanup()
3. Заменить функции вроде close() и ioctl() на их Windows-аналоги

Можно даже написать небольшую программу делающую это автоматически (например на Perl). Она здорово облегчит процесс порта приложений.

Все примеры из статьи (exe + исходники) можно скачать
здесь.

Netinet in h windows

netinet/in.h — Internet address family

SYNOPSIS

DESCRIPTION

The header shall define the following types:

in_port_t Equivalent to the type uint16_t as defined in . in_addr_t Equivalent to the type uint32_t as defined in .

The sa_family_t type shall be defined as described in .

The uint8_t and uint32_t type shall be defined as described in . Inclusion of the header may also make visible all symbols from and .

The header shall define the in_addr structure that includes at least the following member:

The header shall define the sockaddr_in structure that includes at least the following members:

The sin_port and sin_addr members shall be in network byte order.

The sockaddr_in structure is used to store addresses for the Internet address family. Values of this type shall be cast by applications to struct sockaddr for use with socket functions.

[IP6] The header shall define the in6_addr structure that contains at least the following member:

This array is used to contain a 128-bit IPv6 address, stored in network byte order.

The header shall define the sockaddr_in6 structure that includes at least the following members:

The sin6_port and sin6_addr members shall be in network byte order.

The sockaddr_in6 structure shall be set to zero by an application prior to using it, since implementations are free to have additional, implementation-defined fields in sockaddr_in6.

The sin6_scope_id field is a 32-bit integer that identifies a set of interfaces as appropriate for the scope of the address carried in the sin6_addr field. For a link scope sin6_addr, the application shall ensure that sin6_scope_id is a link index. For a site scope sin6_addr, the application shall ensure that sin6_scope_id is a site index. The mapping of sin6_scope_id to an interface or set of interfaces is implementation-defined.

Читайте также:  Windows eee pc 904

The header shall declare the following external variable:

This variable is initialized by the system to contain the wildcard IPv6 address. The header also defines the IN6ADDR_ANY_INIT macro. This macro must be constant at compile time and can be used to initialize a variable of type struct in6_addr to the IPv6 wildcard address.

The header shall declare the following external variable:

This variable is initialized by the system to contain the loopback IPv6 address. The header also defines the IN6ADDR_LOOPBACK_INIT macro. This macro must be constant at compile time and can be used to initialize a variable of type struct in6_addr to the IPv6 loopback address.

The header shall define the ipv6_mreq structure that includes at least the following members:

The header shall define the following macros for use as values of the level argument of getsockopt() and setsockopt():

IPPROTO_IP Internet protocol. IPPROTO_IPV6 [IP6] Internet Protocol Version 6. IPPROTO_ICMP Control message protocol. IPPROTO_RAW [RS] Raw IP Packets Protocol. IPPROTO_TCP Transmission control protocol. IPPROTO_UDP User datagram protocol.

The header shall define the following macros for use as destination addresses for connect(), sendmsg(), and sendto():

INADDR_ANY IPv4 local host address. INADDR_BROADCAST IPv4 broadcast address.

The header shall define the following macro to help applications declare buffers of the proper size to store IPv4 addresses in string form:

INET_ADDRSTRLEN 16. Length of the string form for IP.

[IP6] The header shall define the following macro to help applications declare buffers of the proper size to store IPv6 addresses in string form:

INET6_ADDRSTRLEN 46. Length of the string form for IPv6.

The header shall define the following macros, with distinct integer values, for use in the option_name argument in the getsockopt() or setsockopt() functions at protocol level IPPROTO_IPV6:

IPV6_JOIN_GROUP Join a multicast group. IPV6_LEAVE_GROUP Quit a multicast group. IPV6_MULTICAST_HOPS
Multicast hop limit. IPV6_MULTICAST_IF Interface to use for outgoing multicast packets. IPV6_MULTICAST_LOOP
Multicast packets are delivered back to the local application. IPV6_UNICAST_HOPS Unicast hop limit. IPV6_V6ONLY Restrict AF_INET6 socket to IPv6 communications only.

The header shall define the following macros that test for special IPv6 addresses. Each macro is of type int and takes a single argument of type const struct in6_addr *:

IN6_IS_ADDR_UNSPECIFIED
Unspecified address. IN6_IS_ADDR_LOOPBACK
Loopback address. IN6_IS_ADDR_MULTICAST
Multicast address. IN6_IS_ADDR_LINKLOCAL
Unicast link-local address. IN6_IS_ADDR_SITELOCAL
Unicast site-local address. IN6_IS_ADDR_V4MAPPED
IPv4 mapped address. IN6_IS_ADDR_V4COMPAT
IPv4-compatible address. IN6_IS_ADDR_MC_NODELOCAL
Multicast node-local address. IN6_IS_ADDR_MC_LINKLOCAL
Multicast link-local address. IN6_IS_ADDR_MC_SITELOCAL
Multicast site-local address. IN6_IS_ADDR_MC_ORGLOCAL
Multicast organization-local address. IN6_IS_ADDR_MC_GLOBAL
Multicast global address.

APPLICATION USAGE

RATIONALE

FUTURE DIRECTIONS

SEE ALSO

CHANGE HISTORY

First released in Issue 6. Derived from the XNS, Issue 5.2 specification.

The sin_zero member was removed from the sockaddr_in structure as per The Open Group Base Resolution bwg2001-004.

IEEE Std 1003.1-2001/Cor 1-2002, item XBD/TC1/D6/12 is applied, adding const qualifiers to the in6addr_any and in6addr_loopback external variables.

IEEE Std 1003.1-2001/Cor 2-2004, item XBD/TC2/D6/22 is applied, making it clear which structure members are in network byte order.

Оцените статью