Socket是一个很强大的东西,在Linux上有个概念就是一切皆文件.当然这个说法不严谨,比如进程就不是文件,哈哈,但是我们平常还是可以用这个概念的,就像经典力学和量子力学的关系一样,经典力学在常规条件下还是成立的,Linux中的设备目前有3大类,分别为:字符设备、块设备、网络设备,其中字符设备和块设备一般都是通过文件IO操作的,而网络设备则是通过socket套接字来操作的,可见socket的地位.socket除了可以用在网络间通信之外,还可以用在进程间通信,EngPC这里就用到了socket进程间通信,所以,我们这里就讲一下进程间通信,网络通信这一块,如果后面有机会的话,我可能会通过写一个简单的服务器的方式进行讲解.
回到主题先来看一下socket的框架:
无论是网络通信还是进程间通信,都是这个流程,区别就是填写参数的区别.关于每一步是干嘛的,上图中都有说明,我们直接通过代码进行演示进程间通信,下面是一个服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/home/george/1702/lianxi/local_socket/UNIX.domain"
int main(void)
{
socklen_t clt_addr_len;
int listen_fd = -1,
clt_fd = -1,
ret = -1,
i = -1, len = 0;
static char recv_buff[128];
struct sockaddr_un clt_addr;
struct sockaddr_un srv_addr;
listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(listen_fd < 0){
perror("socket failed");
exit(1);
}
// set srv_addr param
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path, UNIX_DOMAIN);
unlink(UNIX_DOMAIN);
// bind socket and addr
ret = bind(listen_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
if(ret < 0){
perror("bind failed");
goto err;
}
// listen port, 1 client port
ret = listen(listen_fd, 1);
if(ret < 0){
perror("listen failed");
goto err;
}
printf("wait client...\n");
// accept client
len = sizeof(clt_addr);
clt_fd = accept(listen_fd, (struct sockaddr*)&clt_addr, &len);
if(clt_fd < 0){
perror("accept failed");
goto err;
}
printf("client connected...\n");
memset(recv_buff, 0, 128);
int num = read(clt_fd, recv_buff, sizeof(recv_buff));
printf("receive num: %d, content: %s\n", num, recv_buff);
close(clt_fd);
close(listen_fd);
unlink(UNIX_DOMAIN);
return 0;
err:
close(listen_fd);
return -1;
}
然后是一个客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/home/george/1702/lianxi/local_socket/UNIX.domain"
int main(void)
{
int connect_fd = -1,
ret = -1;
char send_buf[128];
static struct sockaddr_un srv_addr;
// create unix socket
connect_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(connect_fd < 0){
perror("socket failed");
exit(1);
}
// set srv_addr param
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path, UNIX_DOMAIN);
// connect server
ret = connect(connect_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
if(ret < 0){
perror("connect failed");
close(connect_fd);
exit(1);
}
// send message to server
memset(send_buf, 0, 128);
strcpy(send_buf, "hello girl");
write(connect_fd, send_buf, strlen(send_buf));
close(connect_fd);
return 0;
}
编译之后,我们开启两个shell终端,一个运行服务端,一个运行客户端.首先我们在其中一个运行服务端,然后,服务端会阻塞并监听socket,等待客户端连接,等待有客户端连接,就等待客户端发送数据给服务端,服务端接收到数据显示,因为只是演示,所以这里没有采用循环接收和发送的方式,直接就运行一遍就结束了.服务器端收到数据并显示的效果如下: