相對於其他的幾個IO函數,recvmsg與sendmsg功能更爲強大,當然用起來也更爲複雜。
#include "sys/socket.h"
ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags);
成功時返回讀寫字節數,出錯時候返回-1。
如果send成功返回,並不必然表示連接另一端的進程接受數據。所保證的僅僅是數據已經無錯誤的發送到網絡上。
這2個函數只用於套接字,不能用於普通的I/O讀寫,參數sockfd則是指明要讀寫的套接口。
返回信息都記錄在struct msghdr * msg中。
struct msghdr {
void * msg_name;//協議地址和套接口信息,在非連接的UDP中,發送者要指定對方地址端口,接受方用於的到數據來源,如果不需要的話可以設置爲NULL(在TCP或者連接的UDP中,一般設置爲NULL)。
socklen_t msg_namelen;//上面的長度
struct lovec * msg_lov;
ssize_t msg_lovlen;//和readv和writev一樣
void * msg_control;
socklen_t msg_controllen;
int msg_flags; //用於返回之前flags的控制信息
}
flags用於傳入控制信息,一般包括以下幾個
sand套接字調用標誌
recv套接字調用標誌
樣例1,在TCP中使用 sendmsg與recvmsg
服務器
......
#define MAXSIZE 100
int main(int argc, char ** argu) {
.......
struct msghdr msg;//初始化struct msghdr
msg.msg_name = NULL; //在tcp中,可以設置爲NULL
struct iovec io;//初始化返回數據
io.iov_base = buf; //只用了一個緩衝區
io.iov_len = MAXSIZE; //定義返回數據長度
msg.msg_iov = &io;
msg.msg_iovlen = 1;//只用了一個緩衝區,所以長度爲1
...................
ssize_t recv_size = recvmsg(connfd, &msg, 0);
char * temp = msg.msg_iov[0].iov_base;//獲取得到的數據
temp[recv_size] = '\0';//爲數據末尾添加結束符
printf("get message:%s", temp);
..........................
}
客戶端
..................
#define MAXSIZE 100
int main(int argc, char ** argv) {
.................
struct msghdr msg;//初始化發送信息
msg.msg_name = NULL;
struct iovec io;
io.iov_base = send_buff;
io.iov_len = sizeof(send_buff);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
if(argc != 2) {
printf("please input port");
exit(1);
}
............
ssize_t size = sendmsg(sockfd, &msg, 0);
close(sockfd);
exit(0);
}
這裏控制信息都設置成0,主要是初始化返回信息struct msghdr結構。關於struct iovec這個數據結構,上一篇readv與writev有介紹。
未連接的UDP套接口
服務器
#include "/programe/net/head.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "sys/wait.h"
#include "sys/select.h"
#include "sys/poll.h"
#define MAXSIZE 100
int main(int argc, char ** argv) {
int sockfd;
struct sockaddr_in serv_socket;
struct sockaddr_in * client_socket = (struct sockaddr_in *) malloc (sizeof(struct sockaddr_in));
char buf[MAXSIZE + 1];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&serv_socket, sizeof(serv_socket));
serv_socket.sin_family = AF_INET;
serv_socket.sin_addr.s_addr = htonl(INADDR_ANY);
serv_socket.sin_port = htons(atoi(argv[1]));
bind(sockfd, (struct sockaddr *)&serv_socket, sizeof(serv_socket));
struct msghdr msg;
msg.msg_name = client_socket;
//如果想得到對方的地址和端口,一定要把初始化完畢的內存頭指針放入msg之中
msg.msg_namelen = sizeof(struct sockaddr_in);//長度也要指定
struct iovec io;
io.iov_base = buf;
io.iov_len = MAXSIZE;
msg.msg_iov = &io;
msg.msg_iovlen = 1;
ssize_t len = recvmsg(sockfd, &msg, 0);
client_socket = (struct sockaddr_in *)msg.msg_name;
char ip[16];
inet_ntop(AF_INET, &(client_socket->sin_addr), ip, sizeof(ip));
int port = ntohs(client_socket->sin_port);
char * temp = msg.msg_iov[0].iov_base;
temp[len] = '\0';
printf("get message from %s[%d]: %s\n", ip, port, temp);
close(sockfd);
}
客戶端
#include "/programe/net/head.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/select.h"
#define MAXSIZE 100
int main(int argc, char ** argv) {
int sockfd;
struct sockaddr_in serv_socket;
int maxfdpl;
char send[] = "hello yuna";
if(argc != 2) {
printf("please input port");
exit(1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&serv_socket, sizeof(serv_socket));
serv_socket.sin_family = AF_INET;
serv_socket.sin_port = htons(atoi(argv[1]));
inet_pton(AF_INET, "192.168.1.235", &serv_socket.sin_addr);
struct msghdr msg;
msg.msg_name = &serv_socket;
msg.msg_namelen = sizeof(struct sockaddr_in);
struct iovec io;
io.iov_base = send;
io.iov_len = sizeof(send);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
ssize_t send_size = sendmsg(sockfd, &msg, 0);
close(sockfd);
exit(0);
}