recv, recvfrom, recvmsg
recv,recvfrom,recvmsg函數用于從套接字接收信息。
ssize_t recv (int s, void *buf, size_t len, int flags);
ssize_t recvfrom (int s, void * restrict buf, size_t len, int flags,
struct sockaddr * restrict from, socklen_t * restrict fromlen);
ssize_t recvmsg (int s, struct msghdr *msg, int flags);
recvfrom和recvmsg系統調用用于從套接字接收消息,也可以用來接受套接字數據,不管其是否是面向連接的。 recv函數通常用于面向連接的套接字(參看[[[Open C 套接字: connect 方法|connect]]),等同于用空指針傳入from參數時
的recvfrom。所有三個例程都返回成功時的消息長度。
recvmsg系統調用使用msghdr結構將直接提供的參數個數減到最少,這個結構具有以下格式,定義在sys/socket.h文件:
struct msghdr {
caddr_t msg_name; /* optional address */
u_int msg_namelen; /* size of address */
struct iovec *msg_iov; /* scatter/gather array */
u_int msg_iovlen; /* # elements in msg_iov */
caddr_t msg_control; /* ancillary data, see below */
u_int msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
下面的代碼片段演示了recv, recvfrom, recvmsg函數的用法:
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void Recv()
{
struct sockaddr_in serv_addr;
int sock_fd;
char line[10];
int size = 10;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serv_addr.sin_port = htons(5000);
sock_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
connect(sock_fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
recv(sock_fd, line, size, 0);
close(sock_fd);
}
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void Sendto()
{
struct sockaddr_in sender_addr;
int sock_fd;
char line[15] = "Hello World!";
unsigned int size = sizeof(sender_addr);
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
sender_addr.sin_family = AF_INET;
sender_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sender_addr.sin_port = htons(5000);
recvfrom(sock_fd,line,13,0,(struct sockaddr*)&sender_addr,&size);
close(sock_fd);
}
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void SendMsgRecvMsg()
{
int sock_fd;
unsigned int sender_len;
struct msghdr msg;
struct iovec iov;
struct sockaddr_in receiver_addr,sender_addr;
char line[10];
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
receiver_addr.sin_family = AF_INET;
receiver_addr.sin_addr.s_addr = htonl(INADDR_ANY);
receiver_addr.sin_port = htons(5000);
bind(sock_fd,(struct sockaddr*)&receiver_addr,sizeof(receiver_addr));
sender_len = sizeof(sender_addr);
msg.msg_name = &sender_addr;
msg.msg_namelen = sender_len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base = line;
msg.msg_iov->iov_len = 10;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
recvmsg(sock_fd,&msg,0);
close(sock_fd);
}
這些調用返回接收的字節數,或者如錯誤發生返回-1。
==========================================================================================
【recv/recvfrom/recvmsg系統調用】
功能描述:
從套接字上接收一個消息。對于recvfrom 和 recvmsg,可同時應用于面向連接的和無連接的套接字。recv一般只用在面向連接的套接字,幾乎等同于recvfrom,只要將recvfrom的第五個參數設置NULL。
如果消息太大,無法完整存放在所提供的緩沖區,根據不同的套接字,多余的字節會丟棄。
假如套接字上沒有消息可以讀取,除了套接字已被設置為非阻塞模式,否則接收調用會等待消息的到來。
用法:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sock, void *buf, size_t len, int flags);
ssize_t recvfrom(int sock, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
ssize_t recvmsg(int sock, struct msghdr *msg, int flags);
參數:
sock:索引將要從其接收數據的套接字。
buf:存放消息接收后的緩沖區。
len:buf所指緩沖區的容量。
flags:是以下一個或者多個標志的組合體,可通過or操作連在一起
MSG_DONTWAIT:操作不會被阻塞。
MSG_ERRQUEUE: 指示應該從套接字的錯誤隊列上接收錯誤值,依據不同的協議,錯誤值以某種輔佐性消息的方式傳遞進來, 使用者應該提供足夠大的緩沖區。導致錯誤的原封包通過msg_iovec作為一般的數據來傳遞。導致錯誤的數據報原目標地址作為msg_name被提供。 錯誤以sock_extended_err結構形態被使用,定義如下
#define SO_EE_ORIGIN_NONE 0
#define SO_EE_ORIGIN_LOCAL 1
#define SO_EE_ORIGIN_ICMP 2
#define SO_EE_ORIGIN_ICMP6 3
struct sock_extended_err
{
u_int32_t ee_errno; /* error number */
u_int8_t ee_origin; /* where the error originated */
u_int8_t ee_type; /* type */
u_int8_t ee_code; /* code */
u_int8_t ee_pad;
u_int32_t ee_info; /* additional information */
u_int32_t ee_data; /* other data */
/* More data may follow */
};
MSG_PEEK:指示數據接收后,在接收隊列中保留原數據,不將其刪除,隨后的讀操作還可以接收相同的數據。
MSG_TRUNC:返回封包的實際長度,即使它比所提供的緩沖區更長, 只對packet套接字有效。
MSG_WAITALL:要求阻塞操作,直到請求得到完整的滿足。然而,如果捕捉到信號,錯誤或者連接斷開發生,或者下次被接收的數據類型不同,仍會返回少于請求量的數據。
MSG_EOR:指示記錄的結束,返回的數據完成一個記錄。
MSG_TRUNC:指明數據報尾部數據已被丟棄,因為它比所提供的緩沖區需要更多的空間。
MSG_CTRUNC:指明由于緩沖區空間不足,一些控制數據已被丟棄。
MSG_OOB:指示接收到out-of-band數據(即需要優先處理的數據)。
MSG_ERRQUEUE:指示除了來自套接字錯誤隊列的錯誤外,沒有接收到其它數據。
from:指向存放對端地址的區域,如果為NULL,不儲存對端地址。
fromlen:作為入口參數,指向存放表示from最大容量的內存單元。作為出口參數,指向存放表示from實際長度的內存單元。
msg:指向存放進入消息頭的內存緩沖,結構形態如下
struct msghdr {
void *msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
struct iovec *msg_iov; /* scatter/gather array */
size_t msg_iovlen; /* # elements in msg_iov */
void *msg_control; /* ancillary data, see below */
socklen_t msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
可能用到的數據結構有
struct cmsghdr {
socklen_t cmsg_len; /* data byte count, including hdr */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by
u_char cmsg_data[]; */
};
返回說明:
成功執行時,返回接收到的字節數。另一端已關閉則返回0。失敗返回-1,errno被設為以下的某個值
EAGAIN:套接字已標記為非阻塞,而接收操作被阻塞或者接收超時
EBADF:sock不是有效的描述詞
ECONNREFUSE:遠程主機阻絕網絡連接
EFAULT:內存空間訪問出錯
EINTR:操作被信號中斷
EINVAL:參數無效
ENOMEM:內存不足
ENOTCONN:與面向連接關聯的套接字尚未被連接上
ENOTSOCK:sock索引的不是套接字
轉載于:https://www.cnblogs.com/hnrainll/archive/2011/08/16/2141480.html
總結
以上是生活随笔為你收集整理的recv, recvfrom, recvmsg的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty中的策略者模式
- 下一篇: 魔戒1