首先介绍两个数据结构及相关的操作函数:struct iovec、struct msghdr
struct iovec {
void * iov_base; /*向量的缓冲地址*/
size_t iov_len; /*向量缓冲区的大小,以字节为单位*/
};
iovec定义在linux/include/uio.h中,此数据结构与readv()和writev()联合使用。
ssize_t readv(int s, const struct iovec *vector, int count);
返回值为成功接收的字节数。 s: 文件描述符 vector:iovec数组的起始地址 count:iovec数组的元素个数。
ssize_t writev(int fd, const iovec *vector, int count);
返回值为成功发送的字节数。 fd:文件描述符 vector:发送数据的vector数组地址 count:iovec数组的元素个数
应用的例子:
/*
服务器端代码
*/ #include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/uio.h>
#include <netinet/in.h>
#define Serv_Port 8888
#define BackLog 5
void process_client_vector(int sock_cli); int main(char *argv[], int argc)
{
int sock_serv, sock_cli;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr; int err;
pid_t handle_client_pid; sock_serv = socket(AF_INET, SOCK_STREAM, );
if(sock_serv < ){
printf("Error When build Socket\n");
return ;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(Serv_Port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); err = bind(sock_serv, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(err < ){
printf("Error When Bind\n");
return ;
} err = listen(sock_serv, BackLog);
if(err < ){
printf("Error When Listen\n");
return ;
} // while(1){
int addrlen = sizeof(struct sockaddr);
printf("Waiteing... ...\n");
sock_cli = accept(sock_serv, (struct sockaddr*)&client_addr, &addrlen); if(sock_cli < )
;//continue;
handle_client_pid = fork();
if(handle_client_pid == ){
close(sock_serv);
process_client_vector(sock_cli);
}
else
close(sock_cli);
// }
} void process_client_vector(int sock_cli)
{
int number;
char str;
char ch;
int i = ;
printf("One client is Accpted\n");
struct iovec *recv_vector = (struct iovec*)malloc(*sizeof(struct iovec)); if(!recv_vector){
printf("NO Enough Space Here\n");
return;
} recv_vector[].iov_base = &number;
recv_vector[].iov_len = sizeof(number); recv_vector[].iov_base = &str;
recv_vector[].iov_len = sizeof(str); recv_vector[].iov_base = &ch;
recv_vector[].iov_len = sizeof(ch); ssize_t size = readv(sock_cli, recv_vector, );
printf("RECVED: Number%d STR: %c CHAR:%c\n",number,str,ch); }
/*
客户器端代码
*/ #include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/uio.h>
#include <netinet/in.h> #define Serv_Port 8888
void process_server_vector(int sock_cli); int main(char *argv[], int argc)
{
struct sockaddr_in server_addr;
int err;
int sock_cli; sock_cli = socket(AF_INET, SOCK_STREAM, );
if(sock_cli < ){
printf("Error When Socket()\n");
return ;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(Serv_Port);
inet_pton(AF_INET, "127.0.0.1",&server_addr.sin_addr); connect(sock_cli, (struct sockaddr *)&server_addr, sizeof(server_addr)); process_server_vector(sock_cli); close(sock_cli); return ;
} void process_server_vector(int sock_cli)
{
int number = ;
char str = 'K';
char ch = 'M';
ssize_t size = ; struct iovec *vector = (struct iovec *)malloc(*sizeof(struct iovec)); vector[].iov_base = &number;
vector[].iov_len = sizeof(number); vector[].iov_base = &str;
vector[].iov_len = sizeof(str); vector[].iov_base = &ch;
vector[].iov_len = sizeof(ch); size = writev(sock_cli, vector, );
if(size < )
printf("Writev Error\n");
}
msghdr 结构体定义在linux/include/socket.h中
struct msghdr {
void *msg_name; /* ptr to socket address structure */
int msg_namelen; /* size of socket address structure */
struct iovec *msg_iov; /* scatter/gather array */
__kernel_size_t msg_iovlen; /* # elements in msg_iov */
void *msg_control; /* ancillary data */
__kernel_size_t msg_controllen; /* ancillary data buffer length */
unsigned int msg_flags; /* flags on received message */
}; 这个数据结构如果不考虑msg_falsgs,与struct iovec的用法并没有很大的差别,操作这个数据结构的函数:
#include<sys/uio.h>
ssize_t recvmsg(int s, const struct msghdr *msg, int flags);
s: 套接字 msg:承接数据的消息数据结构 flags:没有很大的意义,
ssize_t sendmsg(int s, const struct msghdr *msg, int flags );
s: 套接字 msg:承接数据的消息数据结构 flags:决定以什么方式发送数据
readmsg的接收方式取决于msg结构中msg_flags的值,这也是readmsg()与函数sendmsg()的不同的地方,sendmsg()函数的发送方式有参数决定。 在没有介绍套接字的选项前,先不对msghdr的相关代码编写进行实践,因为msghdr中的msg_name,msg_control,msg_flags 等成员的设定与当前使用的协议是相关的,待以后把套接字的选项介绍完后,在深入探究msghdr的使用。 除了上述介绍的几个函数,还有很多的IO函数,现总结如下:
int read(int fd, void * buffer, int nbyte);
int write(int handle, void *buf, int nbyte);
这两个函数可以用于任何的描述符,可以用于文件,标准输入输出,和套接字。 readv(), writev(),recvmsg(),sendmsg()的具体函数参考上面的具体内容。 int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
s: 套接字 buf:数据接收缓冲区 len:接收数据长度 flags:是以下一个或者多个标志的组合体,可通过or操作连在一起
from:数据的来源的地址 fromlen: 地址长度。