栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux编程基础 7.3:套接字编程-3

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux编程基础 7.3:套接字编程-3

1 socket本地通信

socket原本是为网络通讯设计的,但后来在socket框架的基础上发展出了一种IPC(进程通信)机制,即UNIX Domain Socket,专门用来实现使用socket实现的本地进程通信。
本地通信的流程与使用的接口与基于TCP协议的网络通信模型相同,其大致流程如下:

  • (1)调用socket()函数通信双方进程创建各自的socket文件;
  • (2)定义并初始化服务器端进程的地址,并使用bind()函数将其与服务器端进程绑定;
  • (3)调用listen()函数监听客户端进程请求;
  • (4)客户端调用connect()函数,根据已明确的客户端进程地址,向服务器发送请求;
  • (5)服务器端调用accept()函数,处理客户端进程的请求,若客户端与服务器端进程成功建立连接,则双方进程可开始通信;
  • (6)通信双方以数据流的形式通过已创建的连接互相发送和接收数据,进行通信;
  • (7)待通信结束后,通信双方各自调用close()函数关闭连接。

与socket网络通信不同的是,在本地通信中用到的套接字的结构体类型为socket sockaddr_un。

2 本地通信案例

【案例1】使用socket实现本地进程间通信。

dmclient.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define CLI_PATH "/var/tmp/" 
//创建客户端进程,成功返回0,出错返回小于0的errno
int cliConn(const char *paraName){
	int tempFd, tempLen, tempErr, tempRetVal;
	struct sockaddr_un tempSockUn;
	//创建本地套接字domain
	if ((tempFd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
		return(-1);
	}//of if
	//使用自定义地址填充socket地址结构体
	memset(&tempSockUn, 0, sizeof(tempSockUn));
	tempSockUn.sun_family = AF_UNIX;
	sprintf(tempSockUn.sun_path, "%s%05d", CLI_PATH, getpid());
	tempLen = offsetof(struct sockaddr_un, sun_path) + strlen(tempSockUn.sun_path);
	unlink(tempSockUn.sun_path); //避免因文件已存在导致的bind()失败
	if (bind(tempFd, (struct sockaddr *)&tempSockUn, tempLen ) < 0) {
		tempRetVal = -2;
		goto errout;
	}//of if
	//使用服务器进程地址填充socket地址结构体
	memset(&tempSockUn, 0, sizeof(tempSockUn));
	tempSockUn.sun_family = AF_UNIX;
	strcpy(tempSockUn.sun_path, paraName);
	tempLen = offsetof(struct sockaddr_un, sun_path) + strlen(paraName);
	if (connect(tempFd, (struct sockaddr *)&tempSockUn, tempLen) < 0) {
		tempRetVal = -4;
		goto errout;
	}//of if
	return(tempFd);
errout:
	tempErr = errno;
	close(tempFd);
	errno = tempErr;
	return(tempRetVal);
}//of cliConn

int main(void) {
	int tempFd, tempDataLen;
	char tempBuf[1024];
	tempFd = cliConn("foo.socket");		//套接字文件为foo.socket
	if (tempFd < 0) {						//容错处理
		switch (tempFd) {
		case -4:perror("connect"); break;
		case -3:perror("listen"); break;
		case -2:perror("bind"); break;
		case -1:perror("socket"); break;
		}//of switch
		exit(-1);
	}//of if
	while (fgets(tempBuf, sizeof(tempBuf), stdin) != NULL) {
		write(tempFd, tempBuf, strlen(tempBuf));
		tempDataLen = read(tempFd, tempBuf, sizeof(tempBuf));
		write(STDOUT_FILENO, tempBuf, tempDataLen);
	}//of while
	close(fd);
	return 0;
}//of main

dmserver.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define QLEN 10
//创建服务器进程,成功返回0,出错返回小于0的errno
int servListen(const char *paraName) {
	int tempFd, tempLen, tempErr, tempRetVal;
	struct sockaddr_un tempSockUn;
	//创建本地domain套接字
	if ((tempFd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
		return(-1);
	}//of if
	//删除套接字文件,避免因文件存在导致bind()绑定失败	
	unlink(paraName);
	//初始化套接字结构体地址
	memset(&tempSockUn, 0, sizeof(tempSockUn));
	tempSockUn.sun_family = AF_UNIX;
	strcpy(tempSockUn.sun_path, paraName);
	tempLen = offsetof(struct sockaddr_un, sun_path) + strlen(paraName);
	if (bind(tempFd, (struct sockaddr *)&tempSockUn, tempLen) < 0) {
		tempRetVal = -2;
		goto errout;
	}//of if
	if (listen(tempFd, QLEN) < 0) { //告知内核这是一个服务器进程
		tempRetVal = -3;
		goto errout;
	}//of if
	return(tempFd);
errout:
	tempErr = errno;
	close(tempFd);
	errno = tempErr;
	return(tempRetVal);
}//of servListen

int servAccept(int paraListenfd, uid_t *paraUidPtr) {
	int tempCliFd, tempLen, tempErr, tempRetVal;
	time_t tempStaleTime;
	struct sockaddr_un tempSockUn;
	struct stat tempStatBuf;
	tempLen = sizeof(tempSockUn);
	if ((tempCliFd = accept(paraListenfd, (struct sockaddr *)&tempSockUn, &tempLen)) < 0){
		return(-1);
	}//of if
	//从调用地址获取客户端的uid
	tempLen -= offsetof(struct sockaddr_un, sun_path); //获取路径名长度
	tempSockUn.sun_path[tempLen] = 0; 	//为路径名字符串添加终止符
	if (stat(tempSockUn.sun_path, &tempStatBuf) < 0) {
		tempRetVal = -2;
		goto errout;
	}//of if
	if (S_ISSOCK(tempStatBuf.st_mode) == 0) {
		tempRetVal = -3; 				//若返回值为-3,说明这不是一个socket文件
		goto errout;
	}//of if
	if (paraUidPtr != NULL){
		*paraUidPtr = tempStatBuf.st_uid; 		//返回uid的调用者指针
	}//of if
	//到此成功获取路径名
	unlink(tempSockUn.sun_path);
	return(tempCliFd);
errout:
	tempErr = errno;
	close(tempCliFd);
	errno = tempErr;
	return(tempRetVal);
}//of servAccept

int main(void) {
	int tempListenFd, tempAcceptFd, tempDataLen, i;
	uid_t tempAcceptUid;
	char tempBuf[1024];
	tempListenFd = serv_listen("foo.socket");
	if (tempListenFd < 0) {
		switch (tempListenFd) {
		case -3:perror("listen"); break;
		case -2:perror("bind"); break;
		case -1:perror("socket"); break;
		}//of switch
		exit(-1);
	}//of if
	tempAcceptFd = serv_accept(tempListenFd, &tempAcceptUid);
	if (tempAcceptFd < 0) {
		switch (tempAcceptFd) {
		case -3:perror("not a socket"); break;
		case -2:perror("a bad filename"); break;
		case -1:perror("accept"); break;
		}//of switch
		exit(-1);
	}//of if
	while (1) {
	r_again:
		tempDataLen = read(tempAcceptFd, tempBuf, 1024);
		if (tempDataLen == -1) {
			if (errno == EINTR){
				goto r_again;
			}//of if
		} else if (tempDataLen == 0) {
			printf("the other side has been closed.n");
			break;
		}//of if
		for (i = 0; i < n; i++){
			tempBuf[i] = toupper(tempBuf[i]);
		}//of for i
		write(tempAcceptFd, tempBuf, tempDataLen);
	}
	close(tempAcceptFd);
	close(tempListenFd);
	return 0;
}//of main
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883963.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号