socket编程及Unix域内套接字实现进程间通信

在项目中常常需要进程间通讯,但是往往本地socket复杂些,但是更灵活些,毕竟功能强大些

1.socket

int socket(int doamin,int type,int pro);

功能:通过该函数可以创建一个socket套接字文件,并返回该文件的描述符。

参数:domain PF_INET  表示是个互联网程序

PF_UNIX 表示域内套接字,支持单机进程通信

  注:这几个参数有AF_UNIX=AF_LOCAL, PF_UNIX=PF_LOCAL, AF_LOCAL=PF_LOCAL, AF_INET=PF_INET.

typeSOCK_STREAM流式套接字

SOCK_DGRAM 数据报套接字

SOCK_RAW  原始套接字

pro   具体的应用层协议类型,如果该值不清楚,则用0 表示系统自动匹配

  返回值:成功 返回一个文件描述符 ,   失败返回-1

2.bind

int  bind(int sockfd,struct sockaddr * my_addr,int addrlen);

功能:通过该函数可以将本地的ip地址与之前的socket文件描述符关联起来。
参数:sockfd 之前已经创建的套接字id
struct sockaddr
  ip地址结构体

struct sockaddr
{
    u_short sa_family;   //地址族 ===》PF_INET/AF_INET
    char sa_data[14];    //14字节的ip地址信息。协议地址信息。
};//通用地址结构

struct sockaddr_in
{
    u_short sin_family;  // 地址族  PF_INET/AF_INET
    u_short sin_port;     //端口  数字
    struct in_addr sin_addr;// ip地址 整形数字
};
注意:端口和ip信息要处理后加载

struct sockaddr_un {//域内套接字用
    sa_family_t sun_family; /*PF_UNIX或AF_UNIX */
    char sun_path[UNIX_PATH_MAX]; /* 路径名 */
 };

struct in_addr
{
    in_addr_t s_addr;  //ip地址转换成整数后的值
}

addrlen参数2的所占内存空间长度,一般用 sizeof(struct sockaddr_in);

返回值:成功 0    , 失败-1

3.listen

int listen(int sockfd,int backlog);

功能:该函数用于检测sockfd对应的设备文件上有多少个连接进来。

参数:sockfd 之前已经打开并bind的文件描述符

    backlog  允许同时接入连接的个数。

返回值:成功 0    ,    失败 -1

4.accept

int accept(int sockfd,struct sockaddr* addr,socklen_t * addrlen);

功能:该函数用于服务器端接收一个连接进来

参数: sockfd  文件描述符id

addr   连接方的ip地址信息。如果不关心对方的地址,则该值可以为NULL;

addrlen 参数2的内存区长度的地址值,一般用len = sizeof(struct sockaddr);&len

注意:该函数默认情况下是阻塞等待客户端的连接

返回值:成功 返回一个新的文件描述符,专门用于之后的通信过程,    失败返回 -1

5.connect

int connect(int sockfd,struct sockaddr* seraddr,int addrlen);

功能:从客户端向服务器发起一次连接请求

参数:sockfd  之前通过socket()函数成功打开的文件描述符 = 它的返回值

seraddr  服务器端的ip地址+端口信息

addrlen 参数2的内存占用大小,一般是 sizeof(struct sockaddr)

返回值:成功 0    失败-1

6.send

ssize_t  send(int sockfd,const void * buff,size_t len,int flags);

功能:用于TCP通信过程中的发送数据

参数:sodkfd 如果是服务器端则改值等于accept的返回值新建的fd

    如果是客户端则该值等于原始的sockfd;

    buff  要发送的数据内存区,一般用数组或者动态申请的内存

    len  要发送的数据长度

    flags 表示阻塞方式发送数据 0 不阻塞  1 阻塞

返回值:成功 实际发送的字节长度,失败返回 -1

7.recv

ssize_t recv(int sockfd,void * buff,size_t len ,int flags);

功能:用于TCP 通信过程中的接收数据

参数:sodkfd 如果是服务器端则改值等于accept的返回值新建的fd

    buff 要接收的数据内存区,一般用数组或者动态申请的内存。

    len 要接收的数据长度。一般是sizeof(buff)

    flags 表示阻塞方式接收数据 

返回值:成功返回接收到的字节数,失败返回 -1

8.close

int close(int fd);

功能:关闭指定的文件描述符即可,如果是服务器端关闭新fd和原始fd

返回值:成功返回 0,失败返回 -1

在使用读写函数时需要注意

send 、 recv  用于TCP 通信

sendto 、recvfrom  用于UDP通信

write 、read 可用于TCP UDP 通信

9.ulink

int unlink(const char* pathname);

功能:unlink从文件系统中删除一个名字,若这个名字是指向这个文件的最后一个链接,并且没有进程处于打开这个文件的状态,则删除这个文件,释放这个文件占用的空间。

如果这个名字是指向这个文件的最后一个链接,但有某个进程处于打开这个文件的状态,则暂时不删除这个文件,要等到打开这个文件的进程关闭这个文件的文件描述符后才删除这个文件。

如果这个名字指向一个符号链接,则删除这个符号链接。

如果这个名字指向一个socket、fifo或者一个设备,则这个socket、fifo、设备的名字被删除,当时打开这些socke、fifo、设备的进程仍然可以使用它们。

返回值:成功返回0,失败返回-1

域内套接字实现进程间通信与网络套接字编程最重要的区别在于bind这个函数,因为域内套接字不指定IP地址和端口号,但是它在使用 struct sockaddr_un 结构体时是需要指定一个文件路径的,而这个文件是在bind函数执行成功后创建的,在调用bind时,如果该文件存在则返回错误,所以一般的在bind函数之前使用unlink删除以前创建的文件,或者在使用完后显示的删除该文件。

下边的是TCP域内套接字实现进程间通信示例

/* 服务器端 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>

#define PATH 	"/home/linux/APUE/server_socket"


int main(int argc, const char *argv[])
{
	int ret;
	int sockfd,connfd;
	struct sockaddr_un serv;
	char buff[1024];

	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("socket error");
		return -2;
	}
	
	unlink(PATH);
	bzero(&serv, sizeof(serv));
	serv.sun_family = AF_UNIX;
	strcpy(serv.sun_path, PATH);

	
	ret = bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));
	if(ret < 0)
	{
		perror("bind error");
		return -3;
	}

	listen(sockfd, 5);

	connfd = accept(sockfd, NULL , NULL);
	if(connfd < 0)
	{
		perror("accept error");
		return -3;
	}
	while(1)
	{
		ret = recv(connfd, buff, sizeof(buff), 0);
		if(ret < 0)
		{
			perror("recv error");
			return -4;
		}
		write(1, buff, ret);
		if(strncmp(buff, "quit", 4) == 0)
			break;
	}
	
	close(connfd);
	close(sockfd);

	return 0;
}

/*  客户端  */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>

#define PATH 	"/home/linux/APUE/server_socket"

int main(int argc, const char *argv[])
{
	int ret;
	int sockfd;
	struct sockaddr_un serv;
	int len;
	char buff[1024];

	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("socket error");
		return -2;
	}
	
	bzero(&serv, sizeof(serv));
	serv.sun_family = AF_UNIX;
	strcpy(serv.sun_path, PATH);
	
	
	ret = connect(sockfd, (struct sockaddr *)&serv, sizeof(serv));
	if(ret < 0)
	{
		perror("connect error");
		return -2;
	}
	
	while(1)
	{
		ret = read(0, buff, sizeof(buff));
		
		ret = send(sockfd, buff, ret, 0);
		if(ret < 0)
		{
			perror("sendto error");
			return -4;
		}
		if(strncmp(buff, "quit", 4) == 0)
			break;
	}

	close(sockfd);

	return 0;
}



下边的是UDP域内套接字实现进程间通信示例

/* 服务器端 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>

#define PATH 	"/home/linux/APUE/server_socket"


int main(int argc, const char *argv[])
{
	int ret;
	int sockfd,connfd;
	struct sockaddr_un serv;
	int len;
	char buff[1024];

	sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
	if(sockfd < 0)
	{
		perror("socket error");
		return -2;
	}
	
	unlink(PATH);
	bzero(&serv, sizeof(serv));
	serv.sun_family = AF_LOCAL;
	strcpy(serv.sun_path, PATH);

	
	ret = bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));
	if(ret < 0)
	{
		perror("bind error");
		return -3;
	}

	len = sizeof(serv);
	while(1)
	{
		ret = recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&serv, &len);
		if(ret < 0)
		{
			perror("recvfrom error");
			return -4;
		}
		write(1, buff, ret);
		if(strncmp(buff, "quit", 4) == 0)
			break;
	}
	
	close(connfd);
	close(sockfd);

	return 0;
}

/* 客户端 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>

#define PATH 	"/home/linux/APUE/server_socket"

int main(int argc, const char *argv[])
{
	int ret;
	int sockfd;
	struct sockaddr_un serv;
	int len;
	char buff[1024];

	sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
	if(sockfd < 0)
	{
		perror("socket error");
		return -2;
	}

	bzero(&serv, sizeof(serv));
	serv.sun_family = AF_UNIX;
	strcpy(serv.sun_path, PATH);

	while(1)
	{
		ret = read(0, buff, sizeof(buff));
		
		ret = sendto(sockfd, buff, ret, 0, (struct sockaddr *)&serv, sizeof(serv));
		if(ret < 0)
		{
			perror("sendto error");
			return -4;
		}
		if(strncmp(buff, "quit", 4) == 0)
			break;
	}

	close(sockfd);

	return 0;
}



下边这个是平时常常用到的使用本地回环IP来实现的

int smartcard_getPIN_jar(int nTimeout_MS,int nFlagSound,unsigned char *pin)
{
	LOGD("%s",__FUNCTION__);
	int ret,i;
	int temp;
	int socket_fd;
	int recv_len = 0;
	int send_len = 0;
	unsigned char recv_buf[1024];
	unsigned char send_buf[1024];

	MyMemset(send_buf,0,sizeof(send_buf));
	send_buf[0] = 0xA5;
	send_buf[1] = 0x5A;//CMD HEAD 2B
	send_buf[2] = 0x00;
	send_buf[3] = 0x06;//CMDTYPE+CMDDATA LEN 2B
	send_buf[4] = 0x02;//CMDTYPE
	send_buf[5] = (nTimeout_MS & 0xFF000000) >> 24;
	send_buf[6] = (nTimeout_MS & 0xFF0000) >> 16;
	send_buf[7] = (nTimeout_MS & 0xFF00) >> 8;
	send_buf[8] = (nTimeout_MS & 0xFF);
	send_buf[9] = nFlagSound;
	send_len = 4 + send_buf[3] + 1;
	//CMDTYPE + CMDDATA 异或和
	temp = 0;
	for(i = 0;i < send_buf[3];i++)
	{
		temp ^= send_buf[4+i];
	}
	send_buf[10] = temp;
	
	socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(socket_fd < 1)
	{
		LOGE("socket err\r\n");
		return 0;
	}
	struct sockaddr_in seraddr;	
	socklen_t len = sizeof(struct sockaddr_in);	
	seraddr.sin_family = AF_INET;	
	seraddr.sin_port   = htons(35386);//设定自己的端口	
	seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	ret = connect(socket_fd,(struct sockaddr*)&seraddr,len);
	if (ret == -1)
	{
		LOGE("connect err\r\n");
		return 0;
	}
	MyPrintfBuff("send_buf:",send_buf, send_len);	
	ret = send(socket_fd,send_buf,send_len,0);
	if(ret < 0)
	{
		LOGE("send err\r\n");
	}
	while(1)
	{
	    	MyMemset(recv_buf,0,sizeof(recv_buf));
		recv_len = recv(socket_fd,recv_buf,sizeof(recv_buf),0);
		
		temp = 0;
		for(i = 0;i < recv_buf[3];i++)
		{
			temp ^= recv_buf[4+i];
		}
		MyPrintfBuff("recv_buf:",recv_buf, recv_len);	
		if(recv_buf[0]==0x5A && recv_buf[4]==0x82 && recv_buf[recv_len - 1] == temp)
		{
			temp = recv_buf[5];
			if(temp == 0x01)
			{
				LOGD("KeyEvent_notifier 0x01");
//				MyMemcpy(pin[n++],&recv_buf[7],recv_buf[6]);
//				KeyEvent_notifier(1,0);//输入一个字符
				continue;
			}
			else if(temp == 0x02)
			{
				LOGD("KeyEvent_notifier 0x02");
//				KeyEvent_notifier(0,0x30);//撤销一个字符(回调无反应)
				continue;
			}
			else if(temp == 0x10)
			{
				LOGD("KeyEvent_notifier 0x10");
//				KeyEvent_notifier(6,0x30);//取消输入(回调异常)
				ret = -1;
				break;
			}
			else if(temp == 0x11)
			{
				LOGE("PIN TimeOut");
//				KeyEvent_notifier(6,0x30);//取消输入(回调异常)
				ret = -1;
				break;
			}
			else if(temp == 0x00)
			{
				MyMemcpy(pin,&recv_buf[7],recv_buf[6]);
				ret = 0;
				break;
			}
		}
	}
	close(socket_fd);
	return ret;
	
}

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的使用本地套接字实现进程间通信的代码样例: **server.py** ```python import socket # 创建套接字对象 server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # 定义套接字文件路径 socket_file = "/tmp/my_socket" # 绑定套接字文件路径 server_socket.bind(socket_file) # 监听连接请求 server_socket.listen() while True: # 接受连接请求 client_socket, client_address = server_socket.accept() print(f"Connection from {client_address}") # 接收消息 message = client_socket.recv(1024) print(f"Received message: {message.decode()}") # 发送响应 response = "Hello from server" client_socket.send(response.encode()) # 关闭连接 client_socket.close() ``` **client.py** ```python import socket # 创建套接字对象 client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # 定义套接字文件路径 socket_file = "/tmp/my_socket" # 连接服务器 client_socket.connect(socket_file) # 发送消息 message = "Hello from client" client_socket.send(message.encode()) # 接收响应 response = client_socket.recv(1024) print(f"Received response: {response.decode()}") # 关闭连接 client_socket.close() ``` 在上述代码中,server.py 作为服务器端,首先创建一个套接字对象,并指定地址族为 UNIX 套接字,类型为 SOCK_STREAM。然后,将套接字文件路径绑定到该套接字上,并开始监听连接请求。当有客户端连接请求时,接受连接请求,并接收客户端发送的消息。接收到消息后,向客户端发送响应,然后关闭连接。 而 client.py 作为客户端,同样创建一个套接字对象,并指定地址族为 UNIX 套接字,类型为 SOCK_STREAM。然后,连接服务器,并发送消息。接收到服务器的响应后,打印响应内容,并关闭连接。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值