赞
踩
这会是一系列文章,讲解的内容也很简单,文章的目的是让自己的知识固话和文档化,以备自己不时的复习,同时也希望能够给予初学者一些帮助。
前面的文章一系列文章有介绍了 linux 下常见的 IPC 机制,如管道、消息队列、信号量、共享内存。
之前有讲到共享内存是最高效的 IPC 方式,但是在 linux 环境下,应用最广泛的可能是 Socket。
Socket 翻译过来就叫做套接字,一般我们指代的 Socket 其实是网络通信的 Socket,它用于在网络中不同的设备之间进行通信。
但 Socket 也可以用于同一台设备中不同的进程通信的,Android 系统开发中,它叫做 LocalSocket,我觉得 LocalSocket 更适合概括它。
那我们在 Linux 下开发,用于在本机不同进程通信的 Socket 就叫做 Unix Domain Socket。
本文就是讲解 Unix Domain Socket。
Socket 通信机制主要有 2 种,TCP 和 UDP.
TCP 是可靠的通信机制。
UDP 是不可靠的通信机制。
本文讲解 UDP 通信步骤,并将给出示例代码.
我初学 Socket 开发时,很烦它,因为我是一个懒人,它的步骤太多了。
但后来克服恐惧后,细细想来,它也很简单,心平气和把他有条理的捋一捋,还是很简单的嘛,再复杂都是套路。
下面细细来讲,其实也不复杂。
通信一般分为服务端和客户端 2 种角色,在 UDP 开发中,两种角色几乎是对等的。
#include <sys/types.h>
#include <sys/socket.h>
int socket (int domain, int type, int protocol)
所以,我们可以这样编码
int fd = socket(AF_UNIX,SOCK_DGRAM,0);
socket 是为了建立套接字,真正要工作的话,还需要进行绑定,在 UDP 中绑定的是一个文件。
int bind (int fd, CONST_SOCKADDR_ARG addr, socklen_t len)
用法如下:
char* server_file = "server.sock";
struct sockaddr_un addr;
memset(&addr,0,sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path,server_file);
UDP 编程中,服务端不需要监听和接受连接
ssize_t sendto (int fd, const void *buf, size_t n,
int flags, CONST_SOCKADDR_ARG addr,
socklen_t addr_len)
如果写入成功就返回实际的消息字节数量,否则返回 -1.
用法如下:
char *p = "OK,I got id!";
//clientaddr 要指定发送对象的地址
int ssize = sendto(fd,p,strlen(p),0,(sockaddr*)&clientaddr,len);
if (ssize < 0)
{
perror("sendto");
return -1;
}
ssize_t recvfrom (int fd, void *restrict buf, size_t n,
int flags, SOCKADDR_ARG addr,
socklen_t *restrict addr_len)
用法如下:
struct sockaddr_un clientaddr;
socklen_t len = sizeof(clientaddr);
char msgrecv[1024];
memset(msgrecv,'\0',1024);
int size = recvfrom(fd,msgrecv,sizeof(msgrecv),0,(sockaddr*)&clientaddr,&len);
if (size < 0)
{
perror("recv");
return -1;
}
int close (int fd)
udpserver.cpp
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <iostream> #include <unistd.h> using namespace std; char* server_file = "server.sock"; int main(int argc,char** argv) { int fd = socket(AF_UNIX,SOCK_DGRAM,0); if (fd < 0) { perror("socket"); return -1; } struct sockaddr_un addr; memset(&addr,0,sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,server_file); if (access(addr.sun_path,0) != -1) { remove(addr.sun_path); } if(bind(fd,(sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind"); return -1; } struct sockaddr_un clientaddr; socklen_t len = sizeof(clientaddr); char msgrecv[1024]; while (1) { memset(msgrecv,'\0',1024); int size = recvfrom(fd,msgrecv,sizeof(msgrecv),0,(sockaddr*)&clientaddr,&len); if (size < 0) { perror("recv"); return -1; } cout << "I'm server,receive a msg: " << msgrecv << " from: " << clientaddr.sun_path << endl; if (strncmp("quit",msgrecv,4) == 0) { cout << "Server is exiting!" << endl; break; } char *p = "OK,I got id!"; int ssize = sendto(fd,p,strlen(p),0,(sockaddr*)&clientaddr,len); if (ssize < 0) { perror("sendto"); return -1; } sleep(1); } if (close(fd) < 0) { perror("close"); return -1; } return 0; }
代码很简单,udpserver 作为服务端,循环接受和打印消息。
如果收到了 quit 的消息就退出。
udpclient.cpp
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <iostream> #include <unistd.h> using namespace std; char* server_file = "server.sock"; char* client_file = "client.sock"; int main(int argc,char** argv) { int fd = socket(AF_UNIX,SOCK_DGRAM,0); if (fd < 0) { perror("socket"); return -1; } struct sockaddr_un addr; memset(&addr,0,sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,client_file); if (access(addr.sun_path,0) != -1) { remove(addr.sun_path); } if(bind(fd,(sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind"); return -1; } struct sockaddr_un clientaddr; socklen_t len = sizeof(clientaddr); char msgrecv[1024]; struct sockaddr_un serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path,server_file); char *p = "Hello,how are you?"; int ssize = sendto(fd,p,strlen(p),0,(sockaddr*)&serveraddr,len); if (ssize < 0) { perror("sendto"); return -1; } int size = recvfrom(fd,msgrecv,sizeof(msgrecv),0,(sockaddr*)&serveraddr,&len); if (size < 0) { perror("recv"); return -1; } cout << "I'm client,receive a msg :" << msgrecv << endl; sleep(2); char* goodbye = "quit"; if (sendto(fd,goodbye,strlen(goodbye),0,(sockaddr*)&serveraddr,len) < 0) { perror("sendto"); return -1; } if (close(fd) < 0) { perror("close"); return -1; } return 0; }
udpclient 作为客户端,发送了两条消息。最后一条是 quit ,目的是结束本次对话。
现在编译代码,然后运行。
g++ udpserver.cpp -o udpserver
g++ udpclient.cpp -o udpclient
./udpserver &
./udpclient
最终结果如下:
I'm server,receive a msg: Hello,how are you? from: client.sock
I'm client,receive a msg :OK,I got id!�
I'm server,receive a msg: quit from: client.sock
Server is exiting!
[1]+ 已完成 ./udpserver
自此,我们已经掌握了最基本的 Unix Domain Socket 中 UDP 通信,应对复杂的业务场景,我们根据实际条件稍作修改就好了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。