7.Linux网络编程-UNIX域套接字

2023-05-16

一:UNIX套接字
用于同一台pc上运行的进程之间通信,它仅仅复制数据,不执行协议处理,不需要增加删除网络报头,无需计算校验和,不产生顺序号,无需发送确认报文。
unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法。

它提供两类套接字,字节流和数据报,分别类似于TCP和UDP。

使用unix域套接字的三个好处:

unix域套接字通常比通信两端位于同一个主机的TCP套接字快出一倍
unix域套接字可用于在同一个主机上的不同进程之间传递描述符
unix能够提供额外的安全检查措施,较新的实现把客户的凭证(用户ID和组ID)提供给服务器
unix域套接字中用于标识客户和服务器的协议地址是普通文件系统中的路径名。

unix域套接字地址结构如下定义:
#include <sys/un.h>

struct sockaddr_un {
    sa_family_t sun_family;/* AF_LOCAL */
    char sun_path[104];/* 以空字符结尾的字符串 */
}

二:实现流式回射服务器

//服务端
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
	do \
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)

void echo_srv(int conn)
{
	char recvbuf[1024];
	int n;
	while(1)
	{
		memset(recvbuf,0,sizeof(recvbuf));
		//不断接收一行数据到recvbuf中
		n=read(conn,recvbuf,sizeof(recvbuf));
		if(n==-1)
		{
			if(n==EINTR)
				continue;
			ERR_EXIT("read");
		}
		//客户端关闭
		else if(n==0)
		{
			printf("client close\n");
			break;
		}
		fputs(recvbuf,stdout);
		write(conn,recvbuf,strlen(recvbuf));
	}
	close(conn);
}
int main(void)
{
	int listenfd;
	//创建一个监听套接字
	//它的协议家族是PF_UNIX,用流式套接字SOCK_STREAM
	if((listenfd=socket(PF_UNIX,SOCK_STREAM,0))<0)
		ERR_EXIT("socket");

	//unlink表示删除这个文件,先删除,再绑定,重新创造了一个文件
	unlink("/tmp/test_socket");

	//初始化一个地址绑定监听
	struct sockaddr_un servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sun_family=AF_UNIX;
	strcpy(servaddr.sun_path,"/tmp/test_socket");

	//绑定
	//绑定的时候会产生test_socket文件
	if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
		ERR_EXIT("bind");
	//监听
	//监听队列的最大值SOMAXCONN
	if(listen(listenfd,SOMAXCONN)<0)
		ERR_EXIT("listen");

	int conn;
	pid_t pid;
	//接受客户端的连接
	while(1)
	{
		//返回一个已连接套接字
		conn=accept(listenfd,NULL,NULL);
		if(conn==-1)
		{
			if(conn==EINTR)
				continue;
			ERR_EXIT("accept");
		}

		pid=fork();
		if(pid==-1)
			ERR_EXIT("fork");

		//pid==0(子进程)说明是客户端,执行回射
		if(pid==0)
		{
			//子进程不需要处理监听
			close(listenfd);
			echo_srv(conn);
			exit(EXIT_SUCCESS);
		}
		//父进程不需要处理连接
		close(conn);
	}
	return 0;
}

//客户端
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
	do \
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)

void echo_cli(int sock)
{
	char sendbuf[1024]={0};
	char recvbuf[1024]={0};
	//不停地从标准输入获取一行数据到一个缓冲区当中
	while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
	{
		//发送给服务器端
		write(sock,sendbuf,strlen(sendbuf));
		//接收回来
		read(sock,recvbuf,sizeof(recvbuf));
		fputs(recvbuf,stdout);
		memset(sendbuf,0,sizeof(sendbuf));
		memset(recvbuf,0,sizeof(recvbuf));
	}
	close(sock);
}
int main(void)
{
	int sock;
	if((sock=socket(PF_UNIX,SOCK_STREAM,0))<0)
		ERR_EXIT("socket");

	struct sockaddr_un servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sun_family=AF_UNIX;
	strcpy(servaddr.sun_path,"/tmp/test_socket");

	if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
		ERR_EXIT("connect");

	//连接成功后,执行回射客户端的函数
	echo_cli(sock);
	return 0;
}

三:实现数据报模式客户/服务器回射程序

//服务端
#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#define MAXLINE 4096
#define UNIX_DGRAM_PATH "/tmp/unix_dgram_path"

void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
    int n;
    socklen_t len;
    char mesg[MAXLINE];

    while(1) {
        len = clilen;
        n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);

        sendto(sockfd, mesg, n, 0, pcliaddr, len);
    }
}

int main(int argc, char **argv)
{ 
    int ret, sockfd;
    struct sockaddr_un cliaddr, servaddr;

    sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        printf("socket error: %s\n", strerror(errno));
        return -1;
    }

    unlink(UNIX_DGRAM_PATH);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strncpy(servaddr.sun_path, UNIX_DGRAM_PATH, sizeof(servaddr.sun_path) - 1);

    ret = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (ret) {
        printf("bind error: %s\n", strerror(errno));
        return -1;
    }

    dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));

}
//客户端
#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>

#define MAXLINE 4096
#define UNIX_DGRAM_PATH "/tmp/unix_dgram_path"

void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen)
{
    int n;
    char sendline[MAXLINE], recvline[MAXLINE + 1];

    while (fgets(sendline, MAXLINE, fp) != NULL) {
        sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

        n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);

        recvline[n] = 0;
        fputs(recvline, stdout);
    }
}

int main(int argc, char **argv)
{ 
    int ret, sockfd;
    struct sockaddr_un cliaddr, servaddr;

    sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        printf("socket error: %s\n", strerror(errno));
        return -1;
    }

    bzero(&cliaddr, sizeof(cliaddr));
    cliaddr.sun_family = AF_LOCAL;
    strncpy(cliaddr.sun_path, tmpnam(NULL), sizeof(cliaddr.sun_path) - 1);

    ret = bind(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
    if (ret) {
        printf("bind error: %s\n", strerror(errno));
        return -1;
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strncpy(servaddr.sun_path, UNIX_DGRAM_PATH, sizeof(servaddr.sun_path) - 1);

    dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    return 0;
}

四:利用socketpair实现全双工通信

#include <sys/socket.h>

int socketpair(int family, int type, int protocol, int sockfd[2]);/* 成功返回非0,失败返回-1 */

@socketpair函数:该函数与unix的pipe函数类似,返回两个彼此连接的描述符
@int :成功返回非0,失败返回-1 
@family:AF_LOCAL
@type:SOCK_STREAM或者SOCK_DGRAM
@protocol:默认为0
@sockfd[2]:新创建的两个套接字描述符作为sockfd[0],sockfd[1]返回
//在父子进程间实现全双工的通信
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
#define ERR_EXIT(m) \
	do \
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)
//父子进程间实现全双工通信
int main(void)
{
	//定义一个数组用来接收套接字对
	int sockfds[2];
	//全双工通信的流管道,sockfds[0]和sockfds[1]都是即可读又可写
	if(socketpair(PF_UNIX,SOCK_STREAM,0,sockfds)<0)
		ERR_EXIT("socketpair");
 
	pid_t pid;
	//在父子进程间实现全双工的通信
	pid=fork();
	if(pid==-1)
		ERR_EXIT("fork");
 
	//父进程
	if(pid>0)
	{
		int val=0;
		close(sockfds[1]);
		while(1)
		{
			++val;
			printf("sending data: %d\n",val);
			//父进程写给子进程
			write(sockfds[0],&val,sizeof(val));
			//sockfds既可读又可写,用于接收回来
			read(sockfds[0],&val,sizeof(val));
			printf("data received: %d\n",val);
		}
	}
	
	//子进程
	else if(pid==0)
	{
		int val;
		close(sockfds[0]);
		while(1)
		{
			//sockfds[1]既能读又能写
			read(sockfds[1],&val,sizeof(val));
			++val;
			write(sockfds[1],&val,sizeof(val));
		}
	}
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

7.Linux网络编程-UNIX域套接字 的相关文章

  • Java_关于垃圾回收机制(GC)的六个知识

    1 垃圾回收机制 xff1a 垃圾回收是一种动态存储管理技术 xff0c 它自动地释放不再被程序引用的对象 xff0c 按照特定的垃圾收集算法来实现资源自动回收的功能 当一个对象不再被引用的时候 xff0c 内存回收它占领的空间 xff0c
  • 树莓派 Nginx+php7搭建网站

    1 6 安装Nginx 43 php7 并且启动 sudo apt get update sudo apt get install nginx sudo apt get install php7 0 fpm php7 0 cli php7
  • Python的GUI编程(一)Label(标签)

    常用Python GUI库有 xff1a 1 Tkinter 2 WxPython 3 PyQT 4 pyGtk 5 Jython 6 MFC 7 PythonCard 8 Dabo 9 AnyGui 10 WPY 11 IronPytho
  • 使用 Drools 规则引擎实现业务逻辑

    要求施加在当今软件产品上的大多数复杂性是行为和功能方面的 xff0c 从而导致组件实现具有复杂的业务逻辑 实现 J2EE 或 J2SE 应用程序中业务逻辑最常见的方法是编写 Java 代码来实现需求文档的规则和逻辑 在大多数情况下 xff0
  • Python的GUI编程(九)Menu(菜单)OptionMenu(为可选菜单)

    在用户界面程序中 菜单以图标和文字的方式展示可用选项 用鼠标选择一个选项 程序的某个行为既被触发 这种行为通常包括比如 打开 保存文件 退出程序 等功能 上下文菜单是一种根据用户当前所在程序位置 上下文 动态生成的菜单 简单程序 xff1a
  • Linux同时使用无线和有线网络

    有时候我们可能同时插入了无线网卡和有线网络 xff0c 但是默认是通过有线网络连接的外网 如果同时需要使用无线网络连接外网以及使用有线网络进行高速局域网连接的话需要将默认网关设置成无线网络 xff1a 使用ip route show分别查看
  • 【Python】计算两个日期相差天数

    Python 计算两个日期相差天数
  • 《Zoom to learn Learn to zoom》学习笔记

    创新点 xff1a 使用真实原始LR和HR图像作为数据进行训练网络 xff0c 区别于其他大部分网络 xff08 用HR图和经过HR图进行下采样的LR图作为网络数据进行训练 xff09 采用由CX loss 改进的CoBi loss作为网络
  • cmake安装以及更新

    直接install cmake wget https cmake org files v3 6 cmake 3 6 2 tar gz span class token function tar span zxvf cmake 3 6 2 t
  • manjaro安装以及配置、安装输入法、向日葵、anaconda、pycharm、QQ

    为什么不用Ubuntu xff0c 用manjaro就不说了 xff0c 直接上步骤吧 xff01 1 做个优盘 找个优盘 xff0c 最好是3 0接口吧 xff0c 我用的2 0有点慢 先下载系统 xff0c 找个自己喜欢的风格 Manj
  • Python编程中的常见语句

    4 1 if条件判断语句 4 1 1 if条件判断语句单分支 单分支格式 xff1a if 判断条件 xff1a 语句块1 else xff1a 语句块2 例 xff1a name 61 input 39 请输入您的用户名 39 if na
  • Linux下创建新用户及用户权限

    一 用户创建 增加用户 1 在root权限下 xff1b 命令 xff1a useradd 43 用户名 xff0c 它不会在 home目录下创建同名文件夹 xff0c 也没有创建密码 xff0c 因此利用这个用户登录系统 xff0c 是登
  • cacert.pem是怎么来的

    小弟最近在搞支付宝支付接口 xff0c 碰到个问题 xff0c help 我看demo中有下面一行代码 xff1a PHP code 1 2 3 ca证书路径地址 xff0c 用于curl中ssl校验 请保证cacert pem文件在当前文
  • mapping文件的编写

    mapping文件的编写 xff08 以及实体类与xml中类型的对应关系 xff09 2017年02月18日 11 31 36 转角人生 阅读数 xff1a 2918 标签 xff1a mapping文件 更多 个人分类 xff1a map
  • java-兔子繁殖问题

    題目 xff1a 古典问题 xff1a 有一对兔子 xff0c 从出生后第3个月起每个月都生一对兔子 xff0c 小兔子长到第三个月后每个月又生一 对兔子 xff0c 假如兔子都不死 xff0c 问每个月的兔子总数为多少 xff1f 64
  • Nginx服务器的安装部署和框架简介

    Nginx服务器的安装部署 1 如何获取Nginx服务器安装文件 Nginx服务器的软件版本包括 Windows版 和 Linux版俩种 官网下载地址为http nginx org en download html 网页上提供了Nginx服
  • error - problem conecting

    解决的办法是在树莓派里安装如下模块 xff1a sudo apt get install tightvncserver 接着reboot重启 xff0c 重新连接即可
  • SQL 日期函数应用实例!!

    sql view plain copy select convert varchar 10 getdate 120 只返回当前日期 xff0c 且为2012 12 12格式 xff08 最有用 xff09 sql view plain co
  • 使用docker-compose搭建Harbor私有仓库

    一 安装docker compose 1 下载docker compose的最新版本 curl L 34 https github com docker compose releases download 1 22 0 docker com
  • Zabbix安装部署

    一 服务端安装配置 1 环境检查 root 64 m01 cat etc redhat release CentOS Linux release 7 4 1708 Core root 64 m01 uname r 3 10 0 693 el

随机推荐

  • Docker安装部署

    一 安装 devicemapper 存储驱动 使用说明 xff1a 为了在生产级别的环境中使用 docker 运行环境 xff0c 必须使用 direct lvm 模式来运行devicemapper 存储驱动 这种模式使用块设备来创建 th
  • MySql安装部署

    下载并安装MySQL官方的 Yum Repository wget i c http dev mysql com get mysql57 community release el7 10 noarch rpm 使用上面的命令就直接下载了安装
  • Nginx安装部署

    Nginx 安装配置 Nginx 34 engine x 34 是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器 xff0c 也是一个 IMAP POP3 SMTP 代理服务器 在高连接并发的情况
  • Rancher安装部署

    直接通过docker镜像来运行我们的rancher xff0c 首先 xff0c 先从镜像中心下载rancher镜像 xff0c 如果是1 x系列的 xff0c 镜像名为rancher server xff0c 而2 x是rancher r
  • form表单提交onclick和onsubmit进行表单验证

    onsubmit只能表单上使用 提交表单前会触发 onclick是按钮等控件使用 用来触发点击事件 在提交表单前 xff0c 一般都会进行数据验证 xff0c 可以选择在submit按钮上的onclick中验证 也可以在onsubmit中验
  • iperf3网络测试工具

    一 iperf能用来做什么 测量网络带宽和网络质量提供网络延迟抖动 数据包丢失率 最大传输单元等统计信息 二 iperf3主要功能介绍 TCP 测试网络带宽支持多线程 xff0c 在客户端与服务端支持多重连接报告MSS MTU值的大小支持T
  • C++多线程5-单例模式详解

    单例模式 xff1a 只允许创建一个类对象 xff0c 实现的关键是将构造函数变为私有 单例模式有几种实现方式 xff1a 懒汉模式饿汉模式线程安全模式 锁实现和call once实现 局部静态变量模式 1 懒汉模式 当需要使用类对象时 x
  • c++多线程1-多线程的创建

    什么是多线程 xff1f 我们可以理解为一个线程执行一个代码段 xff0c 所以多个线程就是执行多个代码段 xff0c 如果当一个线程结束后 xff0c 进程就退出了 xff0c 这个线程我们称之为主线程 每个进程可以有一个或一个以上的线程
  • c++多线程2-线程参数传递需要注意的几个问题

    一 线程的初始化参数需要注意以下几个问题 xff1a 1 回调函数使用引用参数接收值时 xff0c 必须声明为const xff0c 否则报错 xff1b xff08 线程基于数据安全保护的考虑 xff09 2 回调函数必须声明为指针 xf
  • c++11-智能指针

    c 43 43 智能指针 为了更安全地管理动态内存 xff0c c 43 43 11引入了智能指针 xff0c 提供了包括shared ptr unique ptr weak ptr三种不同类型的智能指针 目录结构 xff1a 一 三种指针
  • C++多线程3-共享数据操作保护

    目录 xff1a 1 多线程操作共享数据引出的问题 2 解决多线程操作共享数据的方法 xff1a 锁 3 互斥量mutex的概念和用法 4 lock普通锁的用法 5 lock guard类模板的用法 6 死锁的概念和解决 7 unique
  • C++多线程4-unique_lock详解

    unique lock和lock guard都是可以自动解锁的类 xff0c 但是lock guard更加高效体现在永远在析构函数中解锁 xff0c 而unique lock更加灵活 xff0c 但执行效率会比lock guard低一些 x
  • C++多线程6-条件变量

    1 条件变量 std condition variable是多线程中经常用到的一个类 xff0c 它的头文件为condition variable 它常用的成员函数包括 xff0c wait notify one notify all等 它
  • Centos6.5系统升级软件操作文档

    为什么要用Centos6 5系统 xff1f 答 xff1a 因为计算板官方推荐Centos6 5 为什么要升级软件 xff1f 答 xff1a 软件需支持C 43 43 11相关库 1 系统信息 系统版本 xff1a CentOS 6 5
  • c++11多线程7-异步线程

    异步线程 异步线程的引入解决了线程有依赖关系的情景 c 43 43 11提供了std async xff0c std packaged task xff0c std promise xff0c 三种方法 1 std async std as
  • HTML中meta标签如何正确使用

    HTML中 lt meta gt 标签如何正确使用 如果我们在浏览器中按下F12或者Ctrl 43 shift 43 J xff0c 便可以打开开发者工具 xff0c 在element中即可看到 lt head gt 元素中有不少 lt m
  • 4.Linux网络编程-select和poll模型

    目录 xff1a 1 补充知识 2 简易版回射服务器的实现 3 select模型实现 4 poll模型实现 1 补充知识 span class token comment 显示进程的pid xff1a span span class tok
  • 5.Linux网络编程-select实现超时API

    一 alarm函数设置超时 它的主要功能是设置信号传送闹钟 信号SIGALRM在经过seconds指定的秒数后传送给目前的进程 xff0c 如果在定时未完成的时间内再次调用了alarm函数 xff0c 则后一次定时器设置将覆盖前面的设置 x
  • 6.Linux网络编程-epoll原理

    一 xff1a 对比select发现epoll的有点 要比较epoll相比较select高效在什么地方 xff0c 就需要比较二者做相同事情的方法 要完成对I O流的复用需要完成如下几个事情 xff1a 1 用户态怎么将文件句柄传递到内核态
  • 7.Linux网络编程-UNIX域套接字

    一 xff1a UNIX套接字 用于同一台pc上运行的进程之间通信 xff0c 它仅仅复制数据 xff0c 不执行协议处理 xff0c 不需要增加删除网络报头 xff0c 无需计算校验和 xff0c 不产生顺序号 xff0c 无需发送确认报