linux编程udp端口分配,linux下的网络编程之UDP例程

客户端程序:

//定义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——出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值