Using sys/socket.h functions on windows
I’m attempting to utilize the socket.h functions within Windows. Essentially, I’m currently looking at the sample code at https://beej.us/guide/bgnet/html/multi/clientserver.html#datagram. I understand that socket.h is a Unix function — is there anyway I can easily emulate that environment while compiling this sample code? Does a different IDE / compiler change anything?
Otherwise, I imagine that I need to utilize a virtualized Linux environment, which may be best anyways as the code will most likely be running in a UNIX environment.
3 Answers 3
You have two options:
Cygwin: lets you compile your Unix sources mostly untouched, but ties you to the Cygwin emulation library. This have two implications: general performance -no only network- will probably be less than optimal; and the target environment must have (at run time) the Cygwin DLL installed.
Winsock: this requires you to replace sys/socket.h (BSD sockets library, UNIX standard for the TCP/IP stack) with winsock2.h , and rewrite some parts of the code — not much, but some.
Some related questions with valuable info:
I think you are looking for Winsock library.
Writing cross platform network applications is not easy with what the BSD standard provides you. Sure it will work but you’ll have to make some replacements like replacing ioctl (if needed) with ioctlsocket (on windows). More differences here.
My advice is to use a library that hides these ugly differences and provides a unified way of communicating. I personally use ACE. You have plenty of examples that show you how to create a server and a client. Copy from the samples and see how they do it there. Their mailing lists are of great help also (don’t forget to use the PRF — see the source tree for the Problem-Report-Form). You can borrow the books for more information. Important note: by using ace you can use ACE wrapper functions like socket, setsockopt, ioctl etc. without worry that they will not work. Unfortunately this adds a library dependency which is not always an option. But ACE has more powerfull features which I’m sure you’ll like once you discover them. Hints: Reactor, Proactor.
Sys socket h windows
sys/socket.h — main sockets header
SYNOPSIS
DESCRIPTION
The header shall define the type socklen_t, which is an integer type of width of at least 32 bits; see APPLICATION USAGE.
The header shall define the unsigned integer type sa_family_t.
The header shall define the sockaddr structure that includes at least the following members:
The header shall define the sockaddr_storage structure. This structure shall be:
Large enough to accommodate all supported protocol-specific address structures
Aligned at an appropriate boundary so that pointers to it can be cast as pointers to protocol-specific address structures and used to access the fields of those structures without alignment problems
The sockaddr_storage structure shall contain at least the following members:
When a sockaddr_storage structure is cast as a sockaddr structure, the ss_family field of the sockaddr_storage structure shall map onto the sa_family field of the sockaddr structure. When a sockaddr_storage structure is cast as a protocol-specific address structure, the ss_family field shall map onto a field of that structure that is of type sa_family_t and that identifies the protocol’s address family.
The header shall define the msghdr structure that includes at least the following members:
The msghdr structure is used to minimize the number of directly supplied parameters to the recvmsg() and sendmsg() functions. This structure is used as a value— result parameter in the recvmsg() function and value only for the sendmsg() function.
The iovec structure shall be defined as described in .
The header shall define the cmsghdr structure that includes at least the following members:
The cmsghdr structure is used for storage of ancillary data object information.
Ancillary data consists of a sequence of pairs, each consisting of a cmsghdr structure followed by a data array. The data array contains the ancillary data message, and the cmsghdr structure contains descriptive information that allows an application to correctly parse the data.
The values for cmsg_level shall be legal values for the level argument to the getsockopt() and setsockopt() functions. The system documentation shall specify the cmsg_type definitions for the supported protocols.
Ancillary data is also possible at the socket level. The header defines the following macro for use as the cmsg_type value when cmsg_level is SOL_SOCKET:
SCM_RIGHTS Indicates that the data array contains the access rights to be sent or received.
The header defines the following macros to gain access to the data arrays in the ancillary data associated with a message header:
CMSG_DATA(cmsg)
If the argument is a pointer to a cmsghdr structure, this macro shall return an unsigned character pointer to the data array associated with the cmsghdr structure. CMSG_NXTHDR(mhdr,cmsg)
If the first argument is a pointer to a msghdr structure and the second argument is a pointer to a cmsghdr structure in the ancillary data pointed to by the msg_control field of that msghdr structure, this macro shall return a pointer to the next cmsghdr structure, or a null pointer if this structure is the last cmsghdr in the ancillary data. CMSG_FIRSTHDR(mhdr)
If the argument is a pointer to a msghdr structure, this macro shall return a pointer to the first cmsghdr structure in the ancillary data associated with this msghdr structure, or a null pointer if there is no ancillary data associated with the msghdr structure.
The header shall define the linger structure that includes at least the following members:
The header shall define the following macros, with distinct integer values:
SOCK_DGRAM Datagram socket. SOCK_RAW [RS] 

The header shall define the following macro for use as the level argument of setsockopt() and getsockopt().
SOL_SOCKET Options to be accessed at socket level, not protocol level.
The header shall define the following macros, with distinct integer values, for use as the option_name argument in getsockopt() or setsockopt() calls:
SO_ACCEPTCONN Socket is accepting connections. SO_BROADCAST Transmission of broadcast messages is supported. SO_DEBUG Debugging information is being recorded. SO_DONTROUTE Bypass normal routing. SO_ERROR Socket error status. SO_KEEPALIVE Connections are kept alive with periodic messages. SO_LINGER Socket lingers on close. SO_OOBINLINE Out-of-band data is transmitted in line. SO_RCVBUF Receive buffer size. SO_RCVLOWAT Receive «low water mark». SO_RCVTIMEO Receive timeout. SO_REUSEADDR Reuse of local addresses is supported. SO_SNDBUF Send buffer size. SO_SNDLOWAT Send «low water mark». SO_SNDTIMEO Send timeout. SO_TYPE Socket type.
The header shall define the following macro as the maximum backlog queue length which may be specified by the backlog field of the listen() function:
SOMAXCONN The maximum backlog queue length.
The header shall define the following macros, with distinct integer values, for use as the valid values for the msg_flags field in the msghdr structure, or the flags parameter in recvfrom(), recvmsg(), sendmsg(), or sendto() calls:
MSG_CTRUNC Control data truncated. MSG_DONTROUTE Send without using routing tables. MSG_EOR Terminates a record (if supported by the protocol). MSG_OOB Out-of-band data. MSG_PEEK Leave received data in queue. MSG_TRUNC Normal data truncated. MSG_WAITALL Attempt to fill the read buffer.
The header shall define the following macros, with distinct integer values:
AF_INET Internet domain sockets for use with IPv4 addresses. AF_INET6 [IP6] 

The header shall define the following macros, with distinct integer values:
SHUT_RD Disables further receive operations. SHUT_RDWR Disables further send and receive operations. SHUT_WR Disables further send operations.
The following shall be declared as functions and may also be defined as macros. Function prototypes shall be provided.
Inclusion of may also make visible all symbols from .
APPLICATION USAGE
To forestall portability problems, it is recommended that applications not use values larger than 2 31 -1 for the socklen_t type.
The sockaddr_storage structure solves the problem of declaring storage for automatic variables which is both large enough and aligned enough for storing the socket address data structure of any family. For example, code with a file descriptor and without the context of the address family can pass a pointer to a variable of this type, where a pointer to a socket address structure is expected in calls such as getpeername(), and determine the address family by accessing the received content after the call.
The example below illustrates a data structure which aligns on a 64-bit boundary. An implementation-defined field _ss_align following _ss_pad1 is used to force a 64-bit alignment which covers proper alignment good enough for needs of at least sockaddr_in6 (IPv6) and sockaddr_in (IPv4) address data structures. The size of padding field _ss_pad1 depends on the chosen alignment boundary. The size of padding field _ss_pad2 depends on the value of overall size chosen for the total size of the structure. This size and alignment are represented in the above example by implementation-defined (not required) constants _SS_MAXSIZE (chosen value 128) and _SS_ALIGNMENT (with chosen value 8). Constants _SS_PAD1SIZE (derived value 6) and _SS_PAD2SIZE (derived value 112) are also for illustration and not required. The implementation-defined definitions and structure field names above start with an underscore to denote implementation private name space. Portable code is not expected to access or reference those fields or constants.
RATIONALE
FUTURE DIRECTIONS
SEE ALSO
CHANGE HISTORY
First released in Issue 6. Derived from the XNS, Issue 5.2 specification.
Порт сокетных приложений из 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
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;
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 + исходники) можно скачать
здесь.

