客户端程序:
//定义IP和端口号
#define
DEFAULT_SERVER 127.0.0.1
#define DEFAULT_PORT_UP
1780
#define STR(x)
#x
//定义相关变量
struct addrinfo
hints;
struct addrinfo *result;
struct addrinfo *q;
char host_name[64];
char port_name[64];
static struct timeval push_timeout = {0, (PUSH_TIMEOUT_MS *
1000)};
static char serv_addr[64] = STR(DEFAULT_SERVER);
static char serv_port_up[8] =
STR(DEFAULT_PORT_UP);
//配置socket参数
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; //AF_INET对于IPv4,AF_INET6对于IPv6
hints.ai_socktype =
SOCK_DGRAM;//SOCK_DGRAM对于UDP数据报,SOCK_STREAM对于TCP数据流
//处理名字到地址、服务到端口的转换,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。
i = getaddrinfo(serv_addr,
serv_port_up, &hints, &result);
if (i != 0) {
MSG("ERROR: [up] getaddrinfo on address %s (PORT %s) returned
%s\n", serv_addr, serv_port_up, gai_strerror(i));
exit(EXIT_FAILURE);
}
//根据相关配置建立socket
for (q=result; q!=NULL; q=q->ai_next) {
sock_up = socket(q->ai_family,
q->ai_socktype,q->ai_protocol);//ai_protocol指TCP或UDP
if (sock_up == -1) continue;
else break;
}
if (q == NULL) {
MSG("ERROR: [up] failed to open socket to any of server %s
addresses (port %s)\n", serv_addr, serv_port_up);
i = 1;
for (q=result; q!=NULL; q=q->ai_next) {
//NI_NUMERICHOST: 以数字形式而非名字返回主机地址.
getnameinfo(q->ai_addr,
q->ai_addrlen, host_name, sizeof host_name, port_name, sizeof
port_name, NI_NUMERICHOST);
MSG("INFO: [up] result %i host:%s service:%s\n", i, host_name,
port_name);
++i;
}
exit(EXIT_FAILURE);
}
//connect连接
i = connect(sock_up,
q->ai_addr, q->ai_addrlen);
if (i != 0) {
MSG("ERROR: [up] connect returned %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
freeaddrinfo(result);
//设置接收超时时间
i = setsockopt(sock_up,
SOL_SOCKET, SO_RCVTIMEO, (void *)&push_timeout, sizeof
push_timeout);
if (i != 0) {
MSG("ERROR: [up] setsockopt returned %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
Socket函数说明:
#include
int PASCAL FAR
setsockopt(SOCKET s,int level,int optname,
const char FAR
*optval,int optlen);
s:标识一个套接字的描述符。
level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval缓冲区长度。
//发送数据
send(sock_up, (void
*)buff_up, buff_index, 0);
//接收阻塞等待,超时返回-1,否则返回接收数据长度
j = recv(sock_up, (void *)buff_ack, sizeof
buff_ack, 0);
//关闭socket
shutdown(sock_up, SHUT_RDWR);
服务器端程序:
//定义相关
变量
int sock;
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *q;
char serv_port[8] = "1680";
char host_name[64];
char port_name[64];
struct sockaddr_storage dist_addr;
//设置Socket参数
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
//处理名字到地址、服务到端口的转换,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。
i = getaddrinfo(NULL,
serv_port, &hints, &result);
if (i != 0) {
MSG("ERROR: getaddrinfo returned %s\n",
gai_strerror(i));
exit(EXIT_FAILURE);
}
//建立socket
for (q=result; q!=NULL; q=q->ai_next) {
sock = socket(q->ai_family,
q->ai_socktype,q->ai_protocol);
if (sock == -1) {
continue;
} else {
//绑定地址
i = bind(sock, q->ai_addr,
q->ai_addrlen);
if (i == -1) {
shutdown(sock, SHUT_RDWR);
continue;
} else {
break;
}
}
}
if (q == NULL) {
MSG("ERROR: failed to open socket or to bind to
it\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result);
//等待接收
byte_nb = recvfrom(sock, databuf, sizeof databuf, 0,
(struct sockaddr *)&dist_addr,
&addr_len);
if ((quit_sig == 1) || (exit_sig == 1)) {
exit(EXIT_SUCCESS);
} else if (byte_nb < 0) {
MSG("WARNING: recvfrom returned an error\n");
} else {
break;
}
//打印地址和端口号
i = getnameinfo((struct
sockaddr *)&dist_addr, addr_len, host_name, sizeof host_name,
port_name, sizeof port_name, NI_NUMERICHOST);
if (i == -1) {
MSG("ERROR: getnameinfo returned %s \n",
gai_strerror(i));
exit(EXIT_FAILURE);
}
MSG("INFO: PULL_DATA request received from gateway 0xXX (host %s,
port %s)\n", (uint32_t)(gw_mac >> 32), (uint32_t)(gw_mac
& 0xFFFFFFFF), host_name, port_name);
//发送数据
byte_nb = sendto(sock, (void
*)databuf, buff_index, 0, (struct sockaddr *)&dist_addr,
addr_len);
if (byte_nb == -1) {
MSG("WARNING: sendto returned an error %s\n",
strerror(errno));
} else {
MSG("INFO: packet #%i sent successfully\n", i);
}
---------------------------------------------------------------------------------------------
其中:
struct
sockaddr {
unsigned
short sa_family;
char
sa_data[14];
};
struct
addrinfo
{
int
ai_flags;
int ai_family;
//AF_INET,AF_INET6,UNIX
etc
int
ai_socktype; //STREAM,DATAGRAM,RAW
int
ai_protocol; //IPPROTO_IP,
IPPROTO_IPV4, IPPROTO_IPV6 etc
size_t
ai_addrlen; //length of
ai_addr
char*
ai_canonname; //full
hostname
struct
sockaddr* ai_addr; //addr of
host
struct
addrinfo* ai_next;
}
参数取值说明
ai_family
AF_INET
2 IPv4
AF_INET6 23 IPv6
AF_UNSPEC 0 协议无关
ai_protocol
IPPROTO_IP 0
IP协议
IPPROTO_IPV4 4
IPv4
IPPROTO_IPV6 41
IPv6
IPPROTO_UDP 17
UDP
IPPROTO_TCP 6
TCP
ai_socktype
SOCK_STREAM 1 流
SOCK_DGRAM 2 数据报
value of
ai_falgs:
AI_PASSIVE: Socket address is intended for `bind'.
AI_CANONNAME:Request for canonical name.
AI_NUMERICHOST: Don't use name resolution.
AI_V4MAPPED: IPv4 mapped addresses are
acceptable.
AI_ALL:
Return IPv4 mapped and IPv6
addresses.
AI_ADDRCONFIG:Use configuration of this host to
choose
getaddrinfo函数原型
int
getaddrinfo( const char *hostname, const char *service, const
struct addrinfo *hints, struct addrinfo **result );
参数说明
hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)
service:服务名可以是十进制的端口号,也可以是已定义的服务名称,如ftp、http等
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构体的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:指定的服务既可支持TCP也可支持UDP,所以调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。
result:本函数通过result指针参数返回一个指向addrinfo结构体链表的指针。
返回值:0——成功,非0——出错