Linux下的多路复用和unix套接字的综合使用

多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备好读写时,即返回可操作的描述符的数目,以下场合经常使用:
(1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
(2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
(3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
(4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
(5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

域套接字的使用可以在不同的进程中进行通信,管道由于只能实现具有亲缘关系进程间的通讯,使用收到了很大的限制,命名管道虽然解决了这一问题,但是无论管道还是命名管道都只能实现单向通信(在只创建一个管道的情况下)

现在将两种结合在一起使用,以下为源程序,仅供参考:

服务器端程序:server.c

/**********************************************************************
* 版权所有 (C)2016, GaoSheng。
*
* 文件名称:server.c
* 文件标识:无
* 内容摘要:多路复用与unix域套接字的学习
* 其它说明:服务器端
* 当前版本:V1.0
* 作    者:GaoSheng
* 完成日期:20160406
*
**********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <pthread.h>

#define UNIX_DOMAIN_SERVER "./SERVER"

#define BUF_SIZE 1024

struct sockaddr_un lo_connect_client_addr;
int gUnixDomainFd_Server = -1;//服务器端的套接字

int main(int argc, char *argv[])
{
	fd_set rfds;
	int max_fd = 0;
	int ret_val = 0,readBytes = 0;
	char rcv_buf[BUF_SIZE] = "";
	int name_len = 0;
	
	//服务器端的套接字的创建与绑定
	unlink(UNIX_DOMAIN_SERVER);
	bzero(&lo_connect_client_addr,sizeof(lo_connect_client_addr));
	lo_connect_client_addr.sun_family = AF_UNIX;
	strcpy(lo_connect_client_addr.sun_path,UNIX_DOMAIN_SERVER);
	name_len = strlen(lo_connect_client_addr.sun_path) + sizeof(lo_connect_client_addr.sun_family);

	gUnixDomainFd_Server = socket(AF_UNIX,SOCK_DGRAM,0);//此处采用数据包,无连接的socket,
														//如果使用字节流的话就需要想TCP通讯那样进行监听
	if (gUnixDomainFd_Server < 0)
	{
		perror("cannot created communication send socket");
		return -1;
	}
	
	if (bind(gUnixDomainFd_Server,(struct sockaddr *)&lo_connect_client_addr,name_len) < 0)
	{
		perror("bind gUnixDomainFd_Server error");
		close(gUnixDomainFd_Server);
		return -1;
	}
	
	//读集合的初始化
	FD_ZERO(&rfds);
		
	if (gUnixDomainFd_Server != 1)
		FD_SET(gUnixDomainFd_Server,&rfds);
	
	if (gUnixDomainFd_Server > max_fd)
		max_fd = gUnixDomainFd_Server;
	
	//循环查询可读的文件描述符
	for(;;)
	{
		ret_val = select(max_fd+1,&rfds,NULL,NULL,NULL);
		
		if (ret_val > 0)
		{
			if (FD_ISSET(gUnixDomainFd_Server,&rfds))
			{
				memset(rcv_buf,0,BUF_SIZE);
				readBytes = recv(gUnixDomainFd_Server,rcv_buf,BUF_SIZE,0);
				
				if (readBytes > 0)
				{
					printf("Server recevice :\n%s\n",rcv_buf);
				}
			}
		}
	}

	return 0;
}
客户端程序:client.c

/**********************************************************************
* 版权所有 (C)2016, GaoSheng。
*
* 文件名称:server.c
* 文件标识:无
* 内容摘要:多路复用与unix域套接字的学习
* 其它说明:客户端
* 当前版本:V1.0
* 作    者:GaoSheng
* 完成日期:20160406
*
**********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <pthread.h>

#define UNIX_DOMAIN_SERVER "./SERVER" //域套接字文件

#define BUF_SIZE 1024

struct sockaddr_un lo_connect_server_addr;
int gUnixDomainFd_Client = -1;//客户端的套接字

int main(int argc, char *argv[])
{
	fd_set sfds;
	int max_fd = 0;
	int ret_val = 0,writeBytes = 0;
	struct timeval tv;
	char send_buf[BUF_SIZE] = "1234567";
	pthread_t write_pid;
	
	//初始化域套接字
	unlink(UNIX_DOMAIN_SERVER);
	bzero(&lo_connect_server_addr,sizeof(lo_connect_server_addr));
	lo_connect_server_addr.sun_family = AF_UNIX;
	strcpy(lo_connect_server_addr.sun_path,UNIX_DOMAIN_SERVER);

	gUnixDomainFd_Client = socket(AF_UNIX,SOCK_DGRAM,0);
	if (gUnixDomainFd_Client < 0)
	{
		perror("cannot created communication send socket");
		return -1;
	}
	
	tv.tv_sec = 0;
	tv.tv_usec = 1000;
	
	//写描述符集合的初始化
	FD_ZERO(&sfds);
	if (gUnixDomainFd_Client != 1)
		FD_SET(gUnixDomainFd_Client,&sfds);
	
	if (gUnixDomainFd_Client > max_fd)
		max_fd = gUnixDomainFd_Client;

	//循环查询可以写的文件描述符
	for(;;)
	{
		ret_val = select(max_fd+1,NULL,&sfds,NULL,&tv);

		if (ret_val > 0)
		{
			if (FD_ISSET(gUnixDomainFd_Client,&sfds))
			{
				socklen_t socklen = sizeof(lo_connect_server_addr.sun_family) + strlen(lo_connect_server_addr.sun_path);
				writeBytes = sendto(gUnixDomainFd_Client, send_buf, strlen(send_buf), MSG_NOSIGNAL|MSG_DONTWAIT, (struct sockaddr *)&lo_connect_server_addr, socklen);	
				
				if (writeBytes > 0)
				{
					printf("Client send  :\n%s\n",send_buf);
				}
			}
		}
		
		sleep(1);
	}

	return 0;
}
以上程序运行结果如下:

客户端结果:


服务器端结果:


以上仅个人理解,如有不足欢迎补充


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值