下面為Daytime這個服務的源代碼例子挫掏,同時兼容IPV6和IPV4的地址堡称,最后部分有更多說明乳乌。
單播模式下的Server方代碼:
"listen_server.h":
#ifndef listen__server__h__
#define listen__server__h__
/*
listen_server
creates a server server socket listening at a hostname:service
using the family and socket type specified in the function
arguments.
*/
int
listen_server(const char *hostname,
const char *service,
int?????????family,
int?????????socktype);
#endif
"listen_server.cpp":
#include
#include
#include
#include
#include "listen_server.h"
const int LISTEN_QUEUE=128;
int
listen_server(const char *hostname,
const char *service,
int?????????family,
int?????????socktype)
{
struct addrinfo hints, *res, *ressave;
int n, sockfd;
memset(&hints, 0, sizeof(struct addrinfo));
/*
AI_PASSIVE flag: the resulting address is used to bind
to a socket for accepting incoming connections.
So, when the hostname==NULL, getaddrinfo function will
return one entry per allowed protocol family containing
the unspecified address for that family.
*/
hints.ai_flags????= AI_PASSIVE;
hints.ai_family???= family;
hints.ai_socktype = socktype;
n = getaddrinfo(hostname, service, &hints, &res);
if (n <0) {
fprintf(stderr,
"getaddrinfo error:: [%s]\n",
gai_strerror(n));
return -1;
}
ressave=res;
/*
Try open socket with each address getaddrinfo returned,
until getting a valid listening socket.
*/
sockfd=-1;
while (res) {
sockfd = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if (!(sockfd < 0)) {
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;
close(sockfd);
sockfd=-1;
}
res = res->ai_next;
}
if (sockfd < 0) {
freeaddrinfo(ressave);
fprintf(stderr,
"socket error:: could not open socket\n");
return -1;
}
listen(sockfd, LISTEN_QUEUE);
freeaddrinfo(ressave);
return sockfd;
}
TCP模式 "tcp_daytime_server.cpp":
#include
#include
#include
#include
#include
#include
#include
#include "listen_server.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int listenfd, connfd;
socklen_t addrlen;
char timeStr[256];
struct sockaddr_storage clientaddr;
time_t now;
char clienthost[NI_MAXHOST];
char clientservice[NI_MAXSERV];
/* local server socket listening at daytime port=13 */
listenfd = listen_server( NULL, DAYTIME_PORT,
AF_UNSPEC, SOCK_STREAM);
if (listenfd < 0) {
fprintf(stderr,
"listen_socket error:: could not create listening "
"socket\n");
return -1;
}
for ( ; ;) {
addrlen = sizeof(clientaddr);
/* accept daytime client connections */
connfd = accept(listenfd,
(struct sockaddr *)&clientaddr,
&addrlen);
if (connfd < 0)
continue;
memset(clienthost, 0, sizeof(clienthost));
memset(clientservice, 0, sizeof(clientservice));
getnameinfo((struct sockaddr *)&clientaddr, addrlen,
clienthost, sizeof(clienthost),
clientservice, sizeof(clientservice),
NI_NUMERICHOST);
printf("Received request from host=[%s] port=[%s]\n",
clienthost, clientservice);
/* process daytime request from a client */
memset(timeStr, 0, sizeof(timeStr));
time(&now);
sprintf(timeStr, "%s", ctime(&now));
write(connfd, timeStr, strlen(timeStr));
close(connfd);
}
return 0;
}
UDP模式 "udp_daytime_server.cpp":
#include
#include
#include
#include
#include
#include
#include "listen_server.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int listenfd, n;
socklen_t addrlen;
char *myhost;
char timeStr[256];
struct sockaddr_storage clientaddr;
time_t now;
char b[256];
char clienthost[NI_MAXHOST];
char clientservice[NI_MAXSERV];
myhost=NULL;
if (argc > 1)
myhost=argv[1];
listenfd= listen_server(myhost, DAYTIME_PORT, AF_UNSPEC, SOCK_DGRAM);
if (listenfd < 0) {
fprintf(stderr,
"listen_server error:: could not create listening "
"socket\n");
return -1;
}
addrlen = sizeof(clientaddr);
for ( ; ;) {
n = recvfrom(listenfd,
b,
sizeof(b),
0,
(struct sockaddr *)&clientaddr,
&addrlen);
if (n < 0)
continue;
memset(clienthost, 0, sizeof(clienthost));
memset(clientservice, 0, sizeof(clientservice));
getnameinfo((struct sockaddr *)&clientaddr, addrlen,
clienthost, sizeof(clienthost),
clientservice, sizeof(clientservice),
NI_NUMERICHOST);
printf("Received request from host=[%s] port=[%s]\n",
clienthost, clientservice);
memset(timeStr, 0, sizeof(timeStr));
time(&now);
sprintf(timeStr, "%s", ctime(&now));
n = sendto(listenfd, timeStr, sizeof(timeStr), 0,
(struct sockaddr *)&clientaddr,
addrlen);
}
return 0;
}
單播模式下的Client方代碼:
"connect_client.h":
#ifndef connect__client__h__
#define connect__client__h__
int
connect_client (const char *hostname,
const char *service,
int?????????family,
int?????????socktype);
#endif
"connect_client.cpp":
#include
#include
#include
#include
#include "connect_client.h"
int
connect_client (const char *hostname,
const char *service,
int?????????family,
int?????????socktype)
{
struct addrinfo hints, *res, *ressave;
int n, sockfd;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = socktype;
n = getaddrinfo(hostname, service, &hints, &res);
if (n <0) {
fprintf(stderr,
"getaddrinfo error:: [%s]\n",
gai_strerror(n));
return -1;
}
ressave = res;
sockfd=-1;
while (res) {
sockfd = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if (!(sockfd < 0)) {
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;
close(sockfd);
sockfd=-1;
}
res=res->ai_next;
}
freeaddrinfo(ressave);
return sockfd;
}
TCP模式 "tcp_daytime_client.cpp":
#include
#include
#include
#include
#include
#include
#include "connect_client.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int connfd;
char *myhost;
char timeStr[256];
myhost = "localhost";
if (argc > 1)
myhost = argv[1];
connfd= connect_client(myhost, DAYTIME_PORT, AF_UNSPEC, SOCK_STREAM);
if (connfd < 0) {
fprintf(stderr,
"client error:: could not create connected socket "
"socket\n");
return -1;
}
memset(timeStr, 0, sizeof(timeStr));
while (read(connfd, timeStr, sizeof(timeStr)) > 0)
printf("%s", timeStr);
close(connfd);
return 0;
}
UDP模式 "udp_daytime_client.cpp":
#include
#include
#include
#include
#include
#include
#include "connect_client.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int connfd, n, m;
char *myhost;
char timeStr[256];
char letter;
myhost = "localhost";
if (argc > 1)
myhost=argv[1];
connfd = connect_client(myhost, DAYTIME_PORT, AF_UNSPEC, SOCK_DGRAM);
if (connfd < 0) {
fprintf(stderr,
"client error:: could not create connected socket "
"socket\n");
return -1;
}
letter = '1';
m= write(connfd, &letter, sizeof(letter));
memset(timeStr, 0, sizeof(timeStr));
n = read(connfd,
timeStr,
sizeof(timeStr));
printf("%s\n", timeStr);
close(connfd);
return 0;
}
多播模式下的代碼:
服務端和客戶端共用 "mcastutil.cpp":
#include
#include
#include
#include
#include
#include
#include
#include
#include "mcastutil.h"
int
get_addr (const char *hostname,
const char *service,
int?????????family,
int?????????socktype,
struct sockaddr_storage *addr)
{
struct addrinfo hints, *res, *ressave;
int n, sockfd, retval;
retval = -1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = socktype;
n = getaddrinfo(hostname, service, &hints, &res);
if (n <0) {
fprintf(stderr,
"getaddrinfo error:: [%s]\n",
gai_strerror(n));
return retval;
}
ressave = res;
sockfd=-1;
while (res) {
sockfd = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if (!(sockfd < 0)) {
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
close(sockfd);
memcpy(addr, res->ai_addr, sizeof(*addr);
retval=0;
break;
}
close(sockfd);
sockfd=-1;
}
res=res->ai_next;
}
freeaddrinfo(ressave);
return retval;
}
int
joinGroup(int sockfd, int loopBack, int mcastTTL,
struct sockaddr_storage *addr)
{
int r1, r2, r3, retval;
retval=-1;
switch (addr->ss_family) {
case AF_INET: {
struct ip_mreq??????mreq;
mreq.imr_multiaddr.s_addr=
((struct sockaddr_in *)addr)->sin_addr.s_addr;
mreq.imr_interface.s_addr= INADDR_ANY;
r1= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loopBack, sizeof(loopBack));
if (r1<0)
perror("joinGroup:: IP_MULTICAST_LOOP:: ");
r2= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
&mcastTTL, sizeof(mcastTTL));
if (r2<0)
perror("joinGroup:: IP_MULTICAST_TTL:: ");
r3= setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&mreq, sizeof(mreq));
if (r3<0)
perror("joinGroup:: IP_ADD_MEMBERSHIP:: ");
} break;
case AF_INET6: {
struct ipv6_mreq????mreq6;
memcpy(&mreq6.ipv6mr_multiaddr,
&(((struct sockaddr_in6 *)addr)->sin6_addr),
sizeof(struct in6_addr));
mreq6.ipv6mr_interface= 0; // cualquier interfaz
r1= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
&loopBack, sizeof(loopBack));
if (r1<0)
perror("joinGroup:: IPV6_MULTICAST_LOOP:: ");
r2= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&mcastTTL, sizeof(mcastTTL));
if (r2<0)
perror("joinGroup:: IPV6_MULTICAST_HOPS::??");
r3= setsockopt(sockfd, IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6));
if (r3<0)
perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: ");
} break;
default:
r1=r2=r3=-1;
}
if ((r1>=0) && (r2>=0) && (r3>=0))
retval=0;
return retval;
}
int
isMulticast(struct sockaddr_storage *addr)
{
int retVal;
retVal=-1;
switch (addr->ss_family) {
case AF_INET: {
struct sockaddr_in *addr4=(struct sockaddr_in *)addr;
retVal = IN_MULTICAST(ntohl(addr4->sin_addr.s_addr));
} break;
case AF_INET6: {
struct sockaddr_in6 *addr6=(struct sockaddr_in6 *)addr;
retVal = IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr);
} break;
default:
;
}
return retVal;
}
服務端 "mcastserver.cpp":
#include
#include
#include
#include
#include
#include
#include
#include
#include "mcastutil.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int sockfd, n;
char *mcastaddr;
char timeStr[256];
char b[256];
struct sockaddr_storage clientaddr, addr;
socklen_t addrlen;
time_t now;
char clienthost[NI_MAXHOST];
char clientservice[NI_MAXSERV];
mcastaddr = "FF01::1111";
if (argc ==2)
mcastaddr=argv[1];
memset(&addr, 0, sizeof(addr));
if (get_addr(mcastaddr, DAYTIME_PORT, PF_UNSPEC,
SOCK_DGRAM, &addr) <0)
{
fprintf(stderr, "get_addr error:: could not find multicast "
"address=[%s] port=[%s]\n", mcastaddr, DAYTIME_PORT);
return -1;
}
if (isMulticast(&addr)<0) {
fprintf(stderr,
"This address does not seem a multicast address [%s]\n",
mcastaddr);
return -1;
}
sockfd = socket(addr.ss_family, SOCK_DGRAM, 0);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind error:: ");
close(sockfd);
return -1;
}
if (joinGroup(sockfd, 0 , 8, &addr) <0) {
close(sockfd);
return -1;
}
addrlen=sizeof(clientaddr);
for ( ; ;) {
n = recvfrom(sockfd,
b,
sizeof(b),
0,
(struct sockaddr *)&clientaddr,
&addrlen);
if (n <0)
continue;
memset(clienthost, 0, sizeof(clienthost));
memset(clientservice, 0, sizeof(clientservice));
getnameinfo((struct sockaddr *)&clientaddr, addrlen,
clienthost, sizeof(clienthost),
clientservice, sizeof(clientservice),
NI_NUMERICHOST);
printf("Received request from host=[%s] port=[%s]\n",
clienthost, clientservice);
memset(timeStr, 0, sizeof(timeStr));
time(&now);
sprintf(timeStr, "%s", ctime(&now));
n = sendto(sockfd, timeStr, sizeof(timeStr), 0,
(struct sockaddr *)&addr,
sizeof(addr));
if (n<1)
perror("sendto error:: \n");
}
return 0;
}
客戶端 "mcastclient.cpp":
#include
#include
#include
#include
#include
#include
#include
#include "mcastutil.h"
const char *DAYTIME_PORT="13";
int
main(int argc, char *argv[])
{
int sockfd, n;
char *myhost;
char timeStr[256];
char letter;
struct sockaddr_storage addr, clientaddr;
int addrlen;
socklen_t clientaddrlen;
myhost = "FF01::1111";
if (argc == 2)
myhost=argv[1];
addrlen=sizeof(addr);
memset(&addr, 0, addrlen);
get_addr(myhost, DAYTIME_PORT, PF_UNSPEC, SOCK_DGRAM, &addr);
sockfd = socket(addr.ss_family, SOCK_DGRAM, 0);
if (bind(sockfd, (struct sockaddr *)&addr, addrlen) <0) {
perror("bind error:: \n");
close(sockfd);
return -1;
}
if (joinGroup(sockfd, 0 , 8, &addr) <0) {
close(sockfd);
return -1;
}
letter = '1';
n = sendto(sockfd, &letter, sizeof(letter), 0,
(struct sockaddr *)&addr,
addrlen);
if (n<0) {
perror("sendto error:: ");
close(sockfd);
return -1;
}
memset(timeStr, 0, sizeof(timeStr));
clientaddrlen=sizeof(clientaddr);
n = recvfrom(sockfd,
timeStr,
sizeof(timeStr),
0,
(struct sockaddr *)&clientaddr,
&clientaddrlen);
if (n<0) {
perror("sendto error:: ");
close(sockfd);
return -1;
}
printf("%s\n", timeStr);
close(sockfd);
return 0;
}
不使用主機名或DNS解析時怎么操作
????上面例子中都是用的主機名或者dns解析來得到具體地址的牺六,從hosts文件或者dns解析通過gethostbyname能得到具體的IPV6或IPV4地址陈莽,如下圖示:
內(nèi)核支持雙棧協(xié)議:
????如果要直接使用IPV6地址或IPV4地址,如果內(nèi)核支持雙棧協(xié)議(見下圖)寿烟,則只需要實現(xiàn)成ipv6地址操作即可澈驼,底層內(nèi)核會自動進行ipv6和ipv4地址的轉(zhuǎn)換:
????客戶端代碼IPv6代碼(如果使用ipv4方式,則使用代碼中的注釋IPv4的代碼韧衣,同時注釋掉IPv6的代碼盅藻;另一種方式還是用ipv6代碼,但是服務器端的地址使用::ffff:a.b.c.d方式去進行連接):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXBUF 1024
int main(int argc, char **argv)
{
int sockfd, len;
/* struct sockaddr_in dest; */// IPv4
struct sockaddr_in6 dest;// IPv6
char buffer[MAXBUF + 1];
if (argc != 3) {
printf
("參數(shù)格式錯誤畅铭!正確用法如下:/n/t/t%s IP地址 端口/n/t比如:/t%s 127.0.0.1 80/n此程序用來從某個 IP 地址的服務器某個端口接收最多 MAXBUF 個字節(jié)的消息",
argv[0], argv[0]);
exit(0);
}
/* 創(chuàng)建一個 socket 用于 tcp 通信 */
/* if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { */ // IPv4
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {??????// IPv6
perror("Socket");
exit(errno);
}
printf("socket created/n");
/* 初始化服務器端(對方)的地址和端口信息 */
bzero(&dest, sizeof(dest));
/* dest.sin_family = AF_INET; */??// IPv4
dest.sin6_family = AF_INET6;?????// IPv6
/* dest.sin_port = htons(atoi(argv[2])); */ // IPv4
dest.sin6_port = htons(atoi(argv[2]));?????// IPv6
/* if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { */ // IPv4 ?,argv[1]: 211.43.56.5
if ( inet_pton(AF_INET6, argv[1], &dest.sin6_addr) < 0 ) {?????????????????// IPv6 ?,argv[1]: 2001:f653:98d3::1
perror(argv[1]);
exit(errno);
}
printf("address created/n");
/* 連接服務器 */
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
perror("Connect ");
exit(errno);
}
printf("server connected/n");
/* 接收對方發(fā)過來的消息勃蜘,最多接收 MAXBUF 個字節(jié) */
bzero(buffer, MAXBUF + 1);
/* 接收服務器來的消息 */
len = recv(sockfd, buffer, MAXBUF, 0);
if (len > 0)
printf("接收消息成功:'%s'硕噩,共%d個字節(jié)的數(shù)據(jù)/n",
buffer, len);
else
printf
("消息接收失敗缭贡!錯誤代碼是%d炉擅,錯誤信息是'%s'/n",
errno, strerror(errno));
bzero(buffer, MAXBUF + 1);
strcpy(buffer, "這是客戶端發(fā)給服務器端的消息/n");
/* 發(fā)消息給服務器 */
len = send(sockfd, buffer, strlen(buffer), 0);
if (len < 0)
printf
("消息'%s'發(fā)送失敾岳痢!錯誤代碼是%d谍失,錯誤信息是'%s'/n",
buffer, errno, strerror(errno));
else
printf("消息'%s'發(fā)送成功眶俩,共發(fā)送了%d個字節(jié)!/n",
buffer, len);
/* 關(guān)閉連接 */
close(sockfd);
return 0;
}
服務器端代碼(同時支持IPv4和IPv6的客戶端來連接):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXBUF 1024
int main(int argc, char **argv)
{
int sockfd, new_fd;
socklen_t len;
/* struct sockaddr_in my_addr, their_addr; */ // IPv4
struct sockaddr_in6 my_addr, their_addr; // IPv6
unsigned int myport, lisnum;
char buf[MAXBUF + 1];
if (argv[1])
myport = atoi(argv[1]);
else
myport = 7838;
if (argv[2])
lisnum = atoi(argv[2]);
else
lisnum = 2;
/* if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { */ // IPv4
if ((sockfd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { // IPv6
perror("socket");
exit(1);
} else
printf("socket created/n");
bzero(&my_addr, sizeof(my_addr));
/* my_addr.sin_family = PF_INET; */ // IPv4
my_addr.sin6_family = PF_INET6;????// IPv6
/* my_addr.sin_port = htons(myport); */ // IPv4
my_addr.sin6_port = htons(myport);???// IPv6
if (argv[3])
/* my_addr.sin_addr.s_addr = inet_addr(argv[3]); */ // IPv4
inet_pton(AF_INET6, argv[3], &my_addr.sin6_addr);??// IPv6
else
/* my_addr.sin_addr.s_addr = INADDR_ANY; */ // IPv4 ?,use 0.0.0.0
my_addr.sin6_addr = in6addr_any;????????????// IPv6 ? ? ? ? ? ,use ::
/* if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) */ // IPv4
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in6))??// IPv6
== -1) {
perror("bind");
exit(1);
} else
printf("binded/n");
if (listen(sockfd, lisnum) == -1) {
perror("listen");
exit(1);
} else
printf("begin listen/n");
while (1) {
len = sizeof(struct sockaddr);
if ((new_fd =
accept(sockfd, (struct sockaddr *) &their_addr,
&len)) == -1) {
perror("accept");
exit(errno);
} else
printf("server: got connection from %s, port %d, socket %d/n",
/* inet_ntoa(their_addr.sin_addr), */ // IPv4
inet_ntop(AF_INET6, &their_addr.sin6_addr, buf, sizeof(buf)), // IPv6
/* ntohs(their_addr.sin_port), new_fd); */ // IPv4
their_addr.sin6_port, new_fd); // IPv6
/* 開始處理每個新連接上的數(shù)據(jù)收發(fā) */
bzero(buf, MAXBUF + 1);
strcpy(buf,
"這是在連接建立成功后向客戶端發(fā)送的第一個消息/n只能向new_fd這個用accept函數(shù)新建立的socket發(fā)消息快鱼,不能向sockfd這個監(jiān)聽socket發(fā)送消息颠印,監(jiān)聽socket不能用來接收或發(fā)送消息/n");
/* 發(fā)消息給客戶端 */
len = send(new_fd, buf, strlen(buf), 0);
if (len < 0) {
printf
("消息'%s'發(fā)送失敗抹竹!錯誤代碼是%d线罕,錯誤信息是'%s'/n",
buf, errno, strerror(errno));
} else
printf("消息'%s'發(fā)送成功,共發(fā)送了%d個字節(jié)窃判!/n",
buf, len);
bzero(buf, MAXBUF + 1);
/* 接收客戶端的消息 */
len = recv(new_fd, buf, MAXBUF, 0);
if (len > 0)
printf("接收消息成功:'%s'钞楼,共%d個字節(jié)的數(shù)據(jù)/n",
buf, len);
else
printf
("消息接收失敗袄琳!錯誤代碼是%d询件,錯誤信息是'%s'/n",
errno, strerror(errno));
/* 處理每個新連接上的數(shù)據(jù)收發(fā)結(jié)束 */
}
close(sockfd);
return 0;
}
內(nèi)核只支持隔離棧(獨立棧)協(xié)議:
則無論是客戶端還是服務器端,都必須把ipv4和ipv6分開處理唆樊,客戶端不用說雳殊,使用哪類地址,就使用哪類代碼(參考上面雙棧協(xié)議實現(xiàn)中的注釋來支持ipv4)窗轩,服務器端通過建立兩個套接口夯秃,然后select檢測進來連接的客戶端是ipv4還是ipv6來同時支持ipv4或ipv6的連接:
SOCKET ServSock[FD_SETSIZE];
ADDRINFO AI0, AI1;
ServSock[0] = socket(AF_INET6, SOCK_STREAM, PF_INET6);
ServSock[1] = socket(AF_INET, SOCK_STREAM, PF_INET);
...
bind(ServSock[0], AI0->ai_addr, AI0->ai_addrlen);
bind(ServSock[1], AI1->ai_addr, AI1->ai_addrlen);
...
select(2, &SockSet, 0, 0, 0);
if (FD_ISSET(ServSocket[0], &SockSet)) {
// IPv6 connection csock = accept(ServSocket[0], (LPSOCKADDR)&From, FromLen);
...
}
if (FD_ISSET(ServSocket[1], &SockSet))
// IPv4 connection csock = accept(ServSocket[1], (LPSOCKADDR)&From, FromLen);
...
}