socketpair()函数的声明:
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
int socketpair(
int d,
int type,
int protocol,
int sv[
2]);
socketpair()函数用于创建一对无名的、相互连接的套接子。
如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。
基本用法:
1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功;
3. 读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述副sv[0]和sv[1]是进程共享的,所以读的进程要关闭写描述符, 反之,写的进程关闭读描述符。
举例:
一、读写操作位于同一进程
-
#include <stdio.h>
-
#include <string.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <error.h>
-
#include <errno.h>
-
#include <sys/socket.h>
-
#include <stdlib.h>
-
-
const
char* str =
"SOCKET PAIR TEST.";
-
-
int main(int argc, char* argv[]){
-
char buf[
128] = {
0};
-
int socket_pair[
2];
-
pid_t pid;
-
-
if(socketpair(AF_UNIX, SOCK_STREAM,
0, socket_pair) ==
-1 ) {
-
printf(
"Error, socketpair create failed, errno(%d): %s\n", errno, strerror(errno));
-
return EXIT_FAILURE;
-
}
-
-
int size = write(socket_pair[
0], str,
strlen(str));
-
//可以读取成功;
-
read(socket_pair[
1], buf, size);
-
printf(
"Read result: %s\n",buf);
-
return EXIT_SUCCESS;
-
}
二、读写操作位于不同进程
-
#include <stdio.h>
-
#include <string.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <error.h>
-
#include <errno.h>
-
#include <sys/socket.h>
-
#include <stdlib.h>
-
-
const
char* str =
"SOCKET PAIR TEST.";
-
-
int main(int argc, char* argv[]){
-
char buf[
128] = {
0};
-
int socket_pair[
2];
-
pid_t pid;
-
-
if(socketpair(AF_UNIX, SOCK_STREAM,
0, socket_pair) ==
-1 ) {
-
printf(
"Error, socketpair create failed, errno(%d): %s\n", errno, strerror(errno));
-
return EXIT_FAILURE;
-
}
-
-
pid = fork();
-
if(pid <
0) {
-
printf(
"Error, fork failed, errno(%d): %s\n", errno, strerror(errno));
-
return EXIT_FAILURE;
-
}
else
if(pid >
0) {
-
//关闭另外一个套接字
-
close(socket_pair[
1]);
-
int size = write(socket_pair[
0], str,
strlen(str));
-
printf(
"Write success, pid: %d\n", getpid());
-
-
}
else
if(pid ==
0) {
-
//关闭另外一个套接字
-
close(socket_pair[
0]);
-
read(socket_pair[
1], buf,
sizeof(buf));
-
printf(
"Read result: %s, pid: %d\n",buf, getpid());
-
}
-
-
for(;;) {
-
sleep(
1);
-
}
-
-
return EXIT_SUCCESS;
-
}
sendmsg, recvmsg , send函数的使用
sendmsg, recvmsg , send三个函数的头文件:
-
#include <sys/types.h>
-
#include <sys/socket.h>
sendmsg函数
定义函数
int sendmsg(int s, const strcut msghdr *msg, unsigned int flags);
函数说明:sendmsg()用来将数据由指定的socket传给对方主机.
参数s:为已建立好连线的socket, 如果利用UDP协议则不需经过连线操作.
参数msg:指向欲连线的数据结构内容, 参数flags 一般默认为0, 详细描述请参考send().
返回值:成功返回发送的字节数,出错返回-1
recvmsg函数
定义函数
int recvmsg(int s, struct msghdr *msg, unsigned int flags);
函数说明:recvmsg()用来接收远程主机经指定的socket 传来的数据.
参数s 为已建立好连线的socket, 如果利用UDP 协议则不需经过连线操作.
参数msg 指向欲连线的数据结构内容,
参数flags 一般设0, 详细描述请参考send().
返回值:成功则返回接收到的字符数, 失败则返回-1, 错误原因存于errno 中.
send函数
定义函数:int send(int s, const void * msg, int len, unsigned int falgs);
函数说明:send()用来将数据由指定的socket 传给对方主机.
参数s 为已建立好连接的socket.
参数msg 指向欲连线的数据内容.
参数len 则为数据长度.
参数flags 一般设0, 其他数值定义如下:
MSG_OOB 传送的数据以out-of-band 送出.
MSG_DONTROUTE 取消路由表查询
MSG_DONTWAIT 设置为不可阻断运作
MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断.
返回值:成功则返回实际传送出去的字符数, 失败返回-1. 错误原因存于errno.
结构msghdr
定义如下:
-
struct msghdr
-
{
-
void *msg_name;
//发送或接收数据的地址
-
socklen_t msg_namelen;
//地址长度
-
strcut iovec * msg_iov;
//要发送或接受数据
-
size_t msg_iovlen;
//容器数据长度
-
void * msg_control;
//附属数据
-
size_t msg_controllen;
//附属数据长度
-
int msg_flags;
//接收消息的标志
-
};
返回值:成功则返回实际传送出去的字符数, 失败返回-1, 错误原因存于errno
错误代码:
-
1、EBADF 参数
s 非合法的
socket 处理代码.
-
2、EFAULT 参数中有一指针指向无法存取的内存空间
-
3、ENOTSOCK 参数
s 为一文件描述词, 非socket.
-
4、EINTR 被信号所中断.
-
5、EAGAIN 此操作会令进程阻断, 但参数
s 的
socket 为不可阻断.
-
6、ENOBUFS 系统的缓冲内存不足
-
7、ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确.
附属数据msg_control
结构
控制信息头部本身由下面的C结构定义:
-
struct cmsghdr {
-
socklen_t cmsg_len;
-
int cmsg_level;
-
int cmsg_type;
-
/* u_char cmsg_data[]; */
-
};
其成员描述如下:
-
成员 描述
-
cmsg_len 附属数据的字节计数,这包含结构头的尺寸。这个值是由
CMSG_LEN()宏计算的。
-
cmsg_level 这个值表明了原始的协议级别(例如,SOL_SOCKET)。
-
cmsg_type 这个值表明了控制信息类型(例如,SCM_RIGHTS)。
-
cmsg_data 这个成员并不实际存在,用来指明实际的额外附属数据所在的位置。
用sendmsg来传递数据程序实例
-
/*sendmsg.c*/
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <errno.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
-
int main(int argc,char *argv[])
-
{
-
int ret;
/* 返回值 */
-
int sock[
2];
/* 套接字对 */
-
struct msghdr msg;
-
struct iovec iov[1];
-
char send_buf[
100] =
"it is a test";
-
struct msghdr msgr;
-
struct iovec iovr[1];
-
char recv_buf[
100];
-
-
/* 创建套接字对 */
-
ret = socketpair(AF_LOCAL,SOCK_STREAM,
0,sock);
-
if(ret ==
-1){
-
printf(
"socketpair err\n");
-
return
1;
-
}
-
-
/* sock[1]发送数据到本地主机 */
-
bzero(&msg,
sizeof(msg));
-
msg.msg_name =
NULL;
/* void*类型 NULL本地地址*/
-
msg.msg_namelen =
0;
-
iov[
0].iov_base = send_buf;
-
iov[
0].iov_len =
sizeof(send_buf);
-
msg.msg_iov = iov;
//要发送或接受数据设为iov
-
msg.msg_iovlen =
1;
//1个元素
-
-
printf(
"开始发送数据:\n");
-
printf(
"发送的数据为: %s\n", send_buf);
-
ret = sendmsg(sock[
1], &msg,
0 );
-
if(ret ==
-1 ){
-
printf(
"sendmsg err\n");
-
return
-1;
-
}
-
printf(
"发送成功!\n");
-
-
/* 通过sock[0]接收发送过来的数据 */
-
bzero(&msg,
sizeof(msg));
-
msgr.msg_name =
NULL;
-
msgr.msg_namelen =
0;
-
iovr[
0].iov_base = &recv_buf;
-
iovr[
0].iov_len =
sizeof(recv_buf);
-
msgr.msg_iov = iovr;
-
msgr.msg_iovlen =
1;
-
ret = recvmsg(sock[
0], &msgr,
0);
-
if(ret ==
-1 ){
-
printf(
"recvmsg err\n");
-
return
-1;
-
}
-
printf(
"接收成功!\n");
-
printf(
"收到数据为: %s\n", recv_buf);
-
-
/* 关闭sockets */
-
close(sock[
0]);
-
close(sock[
1]);
-
-
return
0;
-
}
执行程序结果:
-
yu@ubuntu
:~/Linux/
217/pro_pool/socketpair$ gcc -o sendmsg sendmsg.c
-
yu@ubuntu
:~/Linux/
217/pro_pool/socketpair$ ./sendmsg
-
开始发送数据:
-
发送的数据为: it is a test
-
发送成功!
-
接收成功!
-
收到数据为: it is a test
程序分析:由套接字sock[1]发数据到本地主机,由套接字sock[0]接收发送过来的数据。