在项目中常常需要进程间通讯,但是往往本地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;
}