socketpair

参考博客 https://blog.csdn.net/weixin_41010318/article/details/80221283

socketpair简介

socketpair()函数的声明:

#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int d, int type, int protocol, int sv[2])

创建一对无名的、相互连接的套接字
(1)成功返回0,创建好的套接字分别是sv[0]和sv[1]
(2)失败返回-1,错误码保存于errno中

基本用法:

  1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。
    例如,往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
  2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读,会阻塞。
    只能在另一个套接字上(sv[1])上读才能成功。
  3. 读、写操作可以位于同一个进程,也可以位于不同的进程,如父子进程。
    如果是父子进程时,一般会功能分离,一个进程用于读,一个进程用于写。
    因为文件描述符 sv[0] 和 sv[1] 是进程间共享的,所以读的进程要关闭写描述符
    反之,写的进程关闭读描述符。

和管道和命名管道相比,socketpair有以下特点:

  1. 全双工
  2. 可用于任意两个进程之间的通信

一、读写操作位于同一进程

#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;    
}
/test24# ./main1
Read result: SOCKET PAIR TEST.

二、读写操作位于父子进程

#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;    
}
/test24# ./main 
Write success, pid: 2883
Read result: SOCKET PAIR TEST., pid: 2884

三、兄弟进程之间的交互

#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.";
pid_t parent_pid;
pid_t chi1_pid;
pid_t chi2_pid;
 
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; 
    }

	parent_pid = getpid();
	printf("Father, my pid is %d\n", parent_pid);

    pid = fork();
    if(pid < 0) {
        printf("Father, Error, fork failed, errno(%d): %s\n", errno, strerror(errno));
        return EXIT_FAILURE;
    } else if(pid > 0) {
		//父进程
        printf("Father, create Child1 (pid: %d)\n", pid);
		chi1_pid = pid;
    } else if(pid == 0) {
        //关闭另外一个套接字
        close(socket_pair[0]);
		printf("Child1, sleep 5s\n");
		sleep(5);
		printf("Child1, before read from socket_pair[1]\n");
        read(socket_pair[1], buf, sizeof(buf));        
        printf("Child1, read finish: %s\n", buf);
    }

	if (getpid() == parent_pid) {
		pid = fork();
		if(pid < 0) {
			printf("Father, Error, fork failed, errno(%d): %s\n", errno, strerror(errno));
			return EXIT_FAILURE;
		} else if(pid > 0) {
			//父进程
			printf("Father, create Child2 (pid: %d)\n", pid);
			chi2_pid = pid;
		} else if(pid == 0) {
			//关闭另外一个套接字
			close(socket_pair[1]);
			printf("Child2, before write to socket_pair[0]\n");
			int size = write(socket_pair[0], str, strlen(str));
			printf("Child2, write finish: %d\n", size);
		}
	}

    for(;;) {
        sleep(1);
    }

    return EXIT_SUCCESS;    
}
Father, my pid is 3063
Father, create Child1 (pid: 3064)
Child1, sleep 5s
Child2, before write to socket_pair[0]
Father, create Child2 (pid: 3065)
Child2, write finish: 17

Child1, before read from socket_pair[1]
Child1, read finish: SOCKET PAIR TEST.

四、 路人进程间的交互

socket 通信不就是不相干进程间的交互嘛

附录1

参考:https://blog.csdn.net/qq_21792169/article/details/50160327
SOCK_STREAM是基于TCP的,可靠连接,采用字节流方式,即以字节为单位传输字节序列
SOCK_DGRAM是基于UDP的,用于局域网,如广播,数据包传输

附录2

fork()简介
可以创建一个子进程
父进程返回子进程的pid,子进程返回0
getpid()获取当前进程id,getppid()获取父进程的id
循环创建N个子进程模型,每个子进程标识自己的身份

父子进程相同:
刚fork后,data段,text段,堆,栈,环境变量,全局变量,宿主目录位置,
进程工作目录位置,信号处理方式

父子进程不同:
进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集

读时共享、写时复制

父子进程共享:
全局变量、文件描述符、mmap映射区

猜你喜欢

转载自blog.csdn.net/wangkai6666/article/details/118560061