msghdr 与 cmsghdr
struct msghdr {
void* msg_name
int msg_namelen
struct iovec * msg_iov
unsigned long msg_iovlen
void* msg_control
unsigned longmsg_controllen
unsignedmsg_flags
}
结构成员可以分为下面的四组:
1.
套接口地址成员 msg_name 与 msg_namelen ; msg_name
指向要发送或接收信息的套接口地址。 msg_namelen 指明了这个套接口地址的长度。
msg_name 在调用 recvmsg 时指向接收地址,在调用 sendmsg 时指向目的地址。
2.
I/O 向量引用 msg_iov 与 msg_iovlen 它是实际的数据缓冲区,这个
msg_iovlen 是 msg_iov 的个数,不是长度。 msg_iov 成员指向一个
struct iovec 数组。
3.
附属数据缓冲区成员 msg_control 与 msg_controllen ,msg_control 指向附属数据缓冲区,而
msg_controllen 指明了缓冲区大小。
4.
接收信息标记位 msg_flags
struct iovec
{
void *iov_base
unsigned long iov_len
}
有了这个 iovec ,就可以使用 readv 和 writev 函数在一次函数调用中读取或是写入多个缓冲区,显然比多次 read , write 更有效率。 readv 和 writev 的函数原型如下:
#include
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
struct cmsghdr {
unsigned long cmsg_len int cmsg_level
intcmsg_type
}
· cmsg_len 附属数据的字节数,这包含结构头的尺寸,这个值是由 CMSG_LEN() 宏计算的;
· cmsg_level 表明了原始的协议级别 ( 例如, SOL_SOCKET) ;
· cmsg_type 表明了控制信息类型 ( 例如, SCM_RIGHTS ,附属数据对象是文件描述符; SCM_CREDENTIALS ,附属数据对象是一个包含证书信息的结构 )
msghdr 和 cmsghdr: Linux 系统为这些结构提供了一系列的宏来简化我们的工作,这些宏可以在不同的 UNIX 平台之间进行移植:
#include
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh)
输入参数:指向 struct msghdr 结构的指针; 返回指向附属数据缓冲区内的第一个附属对象的 struct cmsghdr 指针。如果不存在附属数据对象则返回的指针值为 NULL 。
struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg)
输入参数:指向 struct msghdr 结构的指针,指向当前 struct cmsghdr 的指针;
这个用于返回下一个附属数据对象的 struct cmsghdr 指针,如果没有下一个附属数据对象,这个宏就会返回 NULL
size_t CMSG_SPACE(size_t length)
输入参数:附属数据缓冲区中的对象大小; 计算 cmsghdr 头结构加上附属数据大小,并包括对其字段和可能的结尾填充字符,注意 CMSG_LEN() 值并不包括可能的结尾填充字符。 CMSG_SPACE() 宏对于确定所需的缓冲区尺寸是十分有用的。 注意如果在缓冲区中有多个附属数据,一定要同时添加多个 CMSG_SPACE() 宏调用来得到所需的总空间。
void *CMSG_DATA(struct cmsghdr *cmsg)
输入参数:指向 cmsghdr 结构的指针
返回跟随在头部以及填充字节之后的附属数据的第一个字节 ( 如果存在 ) 的地址。
size_t CMSG_LEN(size_t length)
输入参数:附属数据缓冲区中的对象大小; 计算 cmsghdr
头结构加上附属数据大小,包括必要的对其字段,这个值用来设置 cmsghdr 对象的 cmsg_len 成员.
int sendmsg(int, const struct msghdr *msg, unsigned int
flags)
int recvmsg(int s, struct msghdr *msg, unsigned int flags)
s, 套接字通道,对于 sendmsg 是发送套接字,对于 recvmsg 则对应于接收套接字;
msg ,信息头结构指针;
flags , 可选的标记位, 这与 send 或是 sendto
函数调用的标记相同。
函数的返回值为实际发送 / 接收的字节数。否则返回 -1 表明发生了错误
sctp
从协议栈的角度看,于tcp,udp同等级别的层次上的。具有tcp和udp不同的优点。从传输的角度看,它可以象tcp那样点对点的那样传输,也可以像udp那样一对多那样传输,但这两种方式对于sctp来说都是建立连接的。下面就介绍这两种方式的编程方式:
UDP那样点对多点的方式(代码片段):
sctpSK = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)
error = sctp_bindx(sctpSK, (struct sockaddr *)&tempSockAddr,
1, SCTP_BINDX_ADD_ADDR)
listen(sctpSK, 1);
typedef union {
struct sctp_initmsg init
struct sctp_sndrcvinfo sndrcvinfo
} _sctp_cmsg_data_t
// buffer and variables used to read data from recvmsg control
messags
char
incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]
// data
buffer
struct
iovec iov
// the
main msghdr structure used to receive/send messages
struct
msghdr inmessage
struct
sockaddr_in msg_name
memset(&inmessage, 0, sizeof(inmessage))
iov.iov_base = malloc(SCTP_RX_BUFFER_SIZE)
if
(iov.iov_base == NULL)
{
exit(EXIT_FAILURE)
}
iov.iov_len = SCTP_RX_BUFFER_SIZE
inmessage.msg_name = &msg_name
inmessage.msg_namelen = sizeof(msg_name)
inmessage.msg_iov = &iov
inmessage.msg_iovlen = 1 //
number of iovs in the inmessage
inmessage.msg_control = incmsg
inmessage.msg_controllen =
sizeof(incmsg)
received = recvmsg(sctpSK, &inmessage, MSG_WAITALL)
解析这个收到到的inmessage相应的代码如下:
union sctp_notification {
struct
{
__u16
sn_type
__u16 sn_flags
__u32 sn_length
}
sn_header
struct
sctp_assoc_change sn_assoc_change
struct
sctp_paddr_change sn_paddr_change
struct
sctp_remote_error sn_remote_error
struct
sctp_send_failed sn_send_failed
struct
sctp_shutdown_event sn_shutdown_event
struct
sctp_adaption_event sn_adaption_event
struct
sctp_pdapi_event sn_pdapi_event
}
具体去我空间看//*********************************************
//功能:LPC2103的UART0演示
//内容:上位机PC以9600的波特率向LPC2103发送一个字符
// LPC2103再返回该字符
#include<lpc2103.h>
#define Fosc 11059200 //晶振
#define Fcclk Fosc*5 //系统频率
#define Fpclk Fcclk/4 //PCLK
#define UART_bps 9600 //波特率
#define u8 unsigned char
//以下是函数声明
void uart_ini(void)
u8 get_char(void)
void put_char(u8)
void put_string(u8*)
int main()
{
u8 zifu
uart_ini()//UART初始化
put_string("Please input a char:")//输出字符串
while(1)
{
zifu=get_char()//接收一个字符
put_string("\nYou have sent:")
put_char(zifu)//发送该字符
}
}
//UART初始化
void uart_ini()
{
unsigned short Fdiv
APBDIV=0// Fpclk = Fcclk/4
PINSEL0=0x05//选择P0.0和P0.1为TXD0和RXD0
U0LCR=0x80//除数锁存访问位打开
Fdiv=(Fpclk/16)/UART_bps//波特率bps=(Fpclk/16)/(U0DLM:U0DLL),计算(U0DLM:U0DLL)
U0DLM = Fdiv / 256//U0DLM放除数高八位
U0DLL = Fdiv % 256//U0DLL放除数低八位
U0LCR=0x03//关闭除数锁存访问位(这时RBR,THR处于可寻址状态),并设定一个字符的位宽为8位
}
//接收一个字符
u8 get_char()
{
while((U0LSR&0x01)==0)//等待接收完成
return(U0RBR)//返回接收的字符
}
//发送一个字符
void put_char(u8 byte)
{
U0THR=byte//发送一个字符
while((U0LSR&0x40)==0)//等待发送完毕
}
//发送字符串
void put_string(u8 *p)
{
for(*p!='\0'p++) //如果不是结束符,就发送
put_char(*p)
}
//**********************************************************
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)