Linux进程间通信——使用数据报套接字

前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用。
 
一、简单回顾——什么是数据报套接字
 
socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。
 
相对于流套接字,数据报套接字的使用更为简单,它是由类型SOCK_DGRAM指定的,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并一需要总是要建立和维持一个连接。
 
二、基于流套接字的客户/服务器的工作流程
使用数据报socket进行进程通信的进程采用的客户/服务器系统是如何工作的呢?
 
1、服务器端
 
与使用流套接字一样,首先服务器应用程序用系统调用socket来创建一个套接安,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。
 
接下来,服务器进程会给套接字起个名字(监听),我们使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。
 
不同的是,然后系统调用recvfrom来接收来自客户程序发送过来的数据。服务器程序对数据进行相应的处理,再通过系统调用sendto把处理后的数据发送回客户程序。
 
与流套接字程序相比:
 
1、在流套接字中的程序中,接收数据是通过系统调用read,而发送数据是通过系统调用write来实现,而在数据报套接字程序中,这是通过recvfrom和sendto调用来实现的。
 
2、使用数据报套接字的服务器程序并不需要listen调用来创建一个队列来存储连接,也不需要accept调用来接收连接并创建一个新的socket描述符
 
2、客户端
 
基于数据报socket的客户端比服务器端简单,同样,客户应用程序首先调用socket来创建一个未命名的套接字,与服务器一样,客户也是通过sendto和recvfrom来向服务器发送数据和从服务器程序接收数据。
 
与流套接字程序相比:
 
使用数据报套接字的客户程序并不需要使用connect系统调用来连接服务器程序,它只要在需要时向服务器所监听的IP端口发送信息和接收从服务器发送回来的数据即可。
 
三、数据报socket的接口及作用
socket的接口函数声明在头文件sys/types.h和sys/socket.h中。
 
1、创建套接字——socket系统调用
 
该函数用来创建一个套接字,并返回一个描述符,该描述符可以用来访问该套接字,它的原型如下:
int socket(int domain, int type, int protocol);
函数中的三个参数分别对应前面所说的三个套接字属性。protocol参数设置为0表示使用默认协议。
 
2、命名(绑定)套接字——bind系统调用
 
该函数把通过socket调用创建的套接字命名,从而让它可以被其他进程使用。对于AF_UNIX,调用该函数后套接字就会关联到一个文件系统路径名,对于AF_INET,则会关联到一个IP端口号。函数原型如下:

int bind( int socket, const struct sockaddr *address, size_t address_len);
成功时返回0,失败时返回-1;
 
3、发送数据——sendto系统调用
 
该函数把缓冲区buffer中的信息给送给指定的IP端口的程序,原型如下:

int sendto(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *to, socklen_t tolen);
buffer中储存着将要发送的数据,len是buffer的长度,而flags在应用中通常被设置为0,to是要发送数据到的程序的IP端口,tolen是to参数的长度。
 
成功时返回发送的数据的字节数,失败时返回-1.
 
4、接收数据——recvfrom系统调用
 
该函数把发送给程序的信息储存在缓冲区buffer中,并记录数据来源的程序IP端口,原型如下:

int recvfrom(int sockfd, void *buffer, size_t len,int flags, struct sockaddr *src_from, socklen_t *src_len);
buffer用于储存接收到的数据,len指定buffer的长度,而flags在应用中通常被设置0,src_from若不为空,则记录数据来源程序的IP端口,若src_len不为空,则其长度信息记录在src_len所指向的变量中。
 
注意:默认情况下,recvfrom是一个阻塞的调用,即直到它接收到数据才会返回。
 
5、关闭socket——close系统调用
 
该系统调用用来终止服务器和客户上的套接字连接,我们应该总是在连接的两端(服务器和客户)关闭套接字。
 
四、进程使用数据报socket进行通信
 
下面用多个客户程序实例和一个服务器程序来演示多个进程如何通过使用数据报socket来进行通信。
 
sockserver2.c是一个服务器程序,它接收客户程序发来的数据,并创建一个子进程来处理客户发送过来的数据,处理过程非常简单,就是把大写字母改为小写。然后把处理后的数据(大写字母对应的小写字母)发送回给客户端。
 
sockclient2.c是一个客户程序,它向服务器程序发送数据,并接收服务器发送过来的处理后的数据(即小写字母),然后把接收到的数据输出到屏幕上。在运行客户程序时,你可以为它提供一个字符作为参数,此时客户程序将把些字符作为要处理的数据发送给服务器,如果不提供一个参数,则默认发送字符A。
 
sockserver2.c的源代码如下:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> int main()
{
int server_sockfd = -;
int server_len = ;
int client_len = ;
char buffer[];
int result = ;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//创建数据报套接字
server_sockfd = socket(AF_INET, SOCK_DGRAM, );
//设置监听IP端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons();
server_len = sizeof(server_addr);
//绑定(命名)套接字
bind(server_sockfd, (struct sockaddr*)&server_addr, server_len);
//忽略子进程停止或退出信号
signal(SIGCHLD, SIG_IGN); while()
{
//接收数据,用client_addr来储存数据来源程序的IP端口
result = recvfrom(server_sockfd, buffer, sizeof(buffer), ,
(struct sockaddr*)&client_addr, &client_len);
if(fork() == )
{
//利用子进程来处理数据
buffer[] += 'a' - 'A';
sleep();
//发送处理后的数据
sendto(server_sockfd, buffer, sizeof(buffer), ,
(struct sockaddr*)&client_addr, client_len);
printf("%c\n", buffer[]);
//注意,一定要关闭子进程,否则程序运行会不正常
exit();
}
}
//关闭套接字
close(server_sockfd);
}

sockclient2.c的源代码如下:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h> int main(int agrc, char *argv[])
{
struct sockaddr_in server_addr;
int server_len = ;
int sockfd = -;
int result = ;
char c = 'A';
//取第一个参数的第一个字符
if(agrc > )
c = argv[][];
//创建数据报套接字
sockfd = socket(AF_INET, SOCK_DGRAM, );
//设置服务器IP端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons();
server_len = sizeof(server_addr);
//向服务器发送数据
sendto(sockfd, &c, sizeof(char), ,
(struct sockaddr*)&server_addr, server_len);
//接收服务器处理后发送过来的数据,由于不关心数据来源,所以把后两个参数设为0
recvfrom(sockfd, &c, sizeof(char), , , );
printf("char from server = %c\n", c);
//关闭套接字
close(sockfd);
exit();
}
运行结果如下:
先运行服务器程序,如下:
 
 
再运行三个客户端:如下:
 
 
在本例子中,我们启动了一个服务器程序和三个客户程序,从运行的结果来看,客户端发送给服务器程序的所有请求都得到了处理,即把大写字母变成了小写。recvfrom调用是阻塞的调用,即只有当接收到数据才会返回。
 
五、数据报套接字与流套接字的比较
 
1、从使用的便利和效率来讲
我们可以看到使用数据报套接字的确是比使用流套接字简单,而且快速。
 
因为使用流套接字的程序,客户程序需要调用connect来创建一个到服务器程序的连接,并需要维持这个连接,服务器程序也需要调用listen来创建一个队列来保存未处理的请求,当有数据到达时,服务器也不需要调用accept来接受连接并创建一个新socket描述符来处理请求。
 
再来看看使用数据报套接字的程序,服务器程序与客户程序所使用的系统调用大致相同,服务器程序只比客户程序多使用了一个bind调用。基于数据报套接字的程序,只需要使用sendto调用来向指定IP端口的程序发送信息,使用recvfrom调用从指向的IP端口接收信息即可。因为它并不需要建立一个连接,接受连接等,所以省去了很多的功夫。
 
2、从使用场合来讲
 
我们知道流套接字是基于TCP/IP协议的,它是一种安全的协议,提供的是一个有序、可靠、双向字节流的连接,发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。所以它比较适合用来发送信息量大的数据文件,或对数据完整性要求较高的文件,如压缩文件、视频文件等
 
而数据报套接字是基于UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高。所以它比较适合发送一些对实时性要求较高,但是对安全性和完整性要求不太高的数据。如我们熟悉的聊天信息,即使有一点的丢失也不会造成理解上的大的问题。

IPC——数据报套接字通信的更多相关文章

  1. IPC——流套接字通信

    Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进 ...

  2. (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  3. Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字 . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级 ...

  4. Linux进程间通信(九):数据报套接字 socket()、bind()、sendto()、recvfrom()、close()

    前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用. 一.简单回顾——什么是数据报套 ...

  5. 网络IPC:套接字之数据传输

    既然将套接字端点表示为文件描述符,那么只要建立连接,就可以使用read和write来通过套接字通信.通过在connect函数里设置对方地址,数据报套接字也可以“连接”.在套接字描述符上采用read和w ...

  6. 网络IPC:套接字之套接字描述符

    套接字是通信端点的抽象.与应用程序要使用文件描述符访问文件一样,访问套接字也需要套接字描述符.套接字描述符在UNIX系统是用文件描述符实现的.事实上,许多处理文件描述符的函数(如read和write) ...

  7. Linux进程间通信——使用数据报套接字

    前一篇文章, Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用. 一.简单回顾——什么是数据报 ...

  8. UNIX环境高级编程 第16章 网络IPC:套接字

    上一章(15章)中介绍了UNIX系统所提供的多种经典进程间通信机制(IPC):管道PIPE.命名管道FIFO.消息队列Message Queue.信号量Semaphore.共享内存Shared Mem ...

  9. Linux 进程间通信(二)(网络IPC:套接字)

    socket描述符 套接字是通信端点的抽象,创建一个套接字使用如下函数: #include <sys/socket.h> int socket(int domain, int type, ...

随机推荐

  1. 拜托,这才是“Uber”的正确读法

    在美国,私家车主可以注册成为Uber司机,这对传统的出租车行业形成了很大的挑战,同时也让Uber始终处于舆论的风口浪尖. 7月14日,美国用车应用Uber正式宣布进入北京市场.在进入中国后,Uber选 ...

  2. Maven默认周期与插件

    运行 cmd mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId= ...

  3. pybombs 安装

    参考:https://github.com/gnuradio/pybombs 先装:pip 然后: pip install PyBOMBS 更新源: pybombs recipes add gr-re ...

  4. 分布式文件系统--GFS

    分布式文件系统 分布式文件系统:当数据集的大小超过一台独立物理计算机的存储能力时,就有必要对它进行分区(partition)并存储到若干台单独的计算机上.管理网络中夸多台计算机存储的文件系统.这种系统 ...

  5. 关于dom节点绑定滑动事件导致浏览器上下滑动失效解决方案--黄丕巧

    1.移动端开发往往需要添加一下自定义的左右滑动事件,但是添加了左右滑动事件之后就要阻止浏览器大默认事件,否则dom节点的滑动事件和浏览器本身的滑动会出现冲突,导致滑动的时候会出现消失瞬间再出现的效果 ...

  6. oracle查看相关用户表

    select TABLE_NAME from user_tables  //当前用户表 select TABLE_NAME from dba_tables  //所有用户表+系统表 select TA ...

  7. 关于javascript里面仿python切片操作数组的使用方法

    其实在使用了好一段时间的 python之后,我觉得最让我念念不忘的并不是python每次在写函数或者循环的时候可以少用{}括号这样的东西(ps:其实也是了..感觉很清爽,而且又开始写js的时候老是想用 ...

  8. 第三百二十一天 how can I 坚持

    上班第一天,感觉时间过得好慢. 心里好烦,做什么都没心情,感觉没有勇气了,虽然早上说了那么多,但不敢去面对了. 咋整? <猪老三><野子>. 好想去看<美人鱼> 不 ...

  9. SQL SERVER安装提示“安装了 Microsoft Visual Studio 2008 的早期版本

    工作共遇到的问题记录: 安装Sql Server 2008 R2时提示错误:“此计算机上安装了 Microsoft Visual Studio 2008 的早期版本.请在安装 SQL Server 2 ...

  10. WebRTC源码分析:音频模块结构分析

    一.概要介绍WebRTC的音频处理流程,见下图: webRTC将音频会话抽象为一个通道Channel,譬如A与B进行音频通话,则A需要建立一个Channel与B进行音频数据传输.上图中有三个Chann ...