热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Linux进程间通信——使用流套接字

本篇文章将会简单地讲述如何使用socket进行简单的网络编程。具有很好的参考价值。下面跟着小编一起来看下吧

前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程。通常我们使用socket进行网络编程,这里将会简单地讲述如何使用socket进行简单的网络编程。

一、什么是socket

socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。

二、套接字的属性

套接字的特性由3个属性确定,它们分别是:域、类型和协议。

1、套接字的域

它指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。另一个域AF_UNIX表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。

2、套接字类型

因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。这里主要讲流套接字。

流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。

与流套接字相对的是由类型SOCK_DGRAM指定的数据报套接字,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并一需要总是要建立和维持一个连接。

3、套接字协议

只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。

三、套接字地址

每个套接字都有其自己的地址格式,对于AF_UNIX域套接字来说,它的地址由结构sockaddr_un来描述,该结构定义在头文件sys/un.h中,它的定义如下:

struct sockaddr_un{ 
  sa_family_t sun_family;//AF_UNIX,它是一个短整型 
  char    sum_path[];//路径名 
}; 

对于AF_INET域套接字来说,它的地址结构由sockaddr_in来描述,它至少包括以下几个成员:

struct sockaddr_in{ 
  short int      sin_family;//AF_INET 
  unsigned short int  sin_port;//端口号 
  struct in_addr    sin_addr;//IP地址 
}; 

而in_addr被定义为:

struct in_addr{ 
  unsigned long int s_addr; 
}; 

四、基于流套接字的客户/服务器的工作流程

使用socket进行进程通信的进程采用的客户/服务器系统是如何工作的呢?

1、服务器端

首先服务器应用程序用系统调用socket来创建一个套接安,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。

接下来,服务器进程会给套接字起个名字,我们使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。

然后,系统调用listen来创建一个队列并将其用于存放来自客户的进入连接。

最后,服务器通过系统调用accept来接受客户的连接。它会创建一个与原有的命名套接不同的新套接字,这个套接字只用于与这个特定客户端进行通信,而命名套接字(即原先的套接字)则被保留下来继续处理来自其他客户的连接。

2、客户端

基于socket的客户端比服务器端简单,同样,客户应用程序首先调用socket来创建一个未命名的套接字,然后将服务器的命名套接字作为一个地址来调用connect与服务器建立连接。

一旦连接建立,我们就可以像使用底层的文件描述符那样用套接字来实现双向数据的通信。

五、流式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、创建套接字队列(监听)——listen系统调用

该函数用来创建一个队列来保存未处理的请求。成功时返回0,失败时返回-1,其原型如下:

int listen(int socket, int backlog); 

backlog用于指定队列的长度,等待处理的进入连接的个数最多不能超过这个数字,否则往后的连接将被拒绝,导致客户的连接请求失败。调用后,程序一直会监听这个IP端口,如果有连接请求,就把它加入到这个队列中。

4、接受连接——accept系统调用

该系统调用用来等待客户建立对该套接字的连接。accept系统调用只有当客户程序试图连接到由socket参数指定的套接字上时才返回,也就是说,如果套接字队列中没有未处理的连接,accept将阻塞直到有客户建立连接为止。accept函数将创建一个新套接字来与该客户进行通信,并且返回新套接字的描述符,新套接字的类型和服务器监听套接字类型是一样的。它的原型如下:

int accept(int socket, struct sockaddr *address, size_t *address_len); 

address为连接客户端的地址,参数address_len指定客户结构的长度,如果客户地址的长度超过这个值,它将会截断。

5、请求连接——connect系统调用

该系统调用用来让客户程序通过在一个未命名套接字和服务器监听套接字之间建立连接的方法来连接到服务器。它的原型如下:

int connect(int socket, const struct sockaddr *address, size_t address_len); 

参数socket指定的套接字连接到参数addres指定的服务器套接字。成功时返回0,失败时返回-1.

6、关闭socket——close系统调用

该系统调用用来终止服务器和客户上的套接字连接,我们应该总是在连接的两端(服务器和客户)关闭套接字。

六、进程使用流式socket进行通信

下面用多个客户程序和一个服务器程序来展示进程间如何利用套接字进行通信。

sockserver.c是一个服务器程序,它首先创建套接字,然后绑定一个端口再监听套接字,忽略子进程的停止消息等,然后它进入循环,一直循环检查是否有客户连接到服务器,如果有,则调用fork创建一个子进程来处理请求。利用read系统调用来读取客户端发来的信息,利用write系统调用来向客户端发送信息。这个服务器的工作非常简单,就是把客户发过来的字符+1,再发送回给客户。

sockclient.c是一个客户程序,它同样要先创建套接,然后连接到指定IP端口服务器,如果连接成功,就用write来发送信息给服务器,再用read获取服务器处理后的信息,再输出。

服务器sockserver.c的源代码如下:

#include  
#include  
#include  
#include  
#include  
#include  
#include  

int main() 
{ 
  int server_sockfd = -1; 
  int client_sockfd = -1; 
  int client_len = 0; 
  struct sockaddr_in server_addr; 
  struct sockaddr_in client_addr; 
  //创建流套接字 
  server_sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  //设置服务器接收的连接地址和监听的端口 
  server_addr.sin_family = AF_INET;//指定网络套接字 
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接 
  server_addr.sin_port = htons(9736);//绑定到9736端口 
  //绑定(命名)套接字 
  bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); 
  //创建套接字队列,监听套接字 
  listen(server_sockfd, 5); 
  //忽略子进程停止或退出信号 
  signal(SIGCHLD, SIG_IGN); 

  while(1) 
  { 
    char ch = '\0'; 
    client_len = sizeof(client_addr); 
    printf("Server waiting\n"); 
    //接受连接,创建新的套接字 
    client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len); 

    if(fork() == 0) 
    { 
      //子进程中,读取客户端发过来的信息,处理信息,再发送给客户端 
      read(client_sockfd, &ch, 1); 
      sleep(5); 
      ch++; 
      write(client_sockfd, &ch, 1); 
      close(client_sockfd); 
      exit(0); 
    } 
    else 
    { 
      //父进程中,关闭套接字 
      close(client_sockfd); 
    } 
  } 
} 

客户sockclient.c的源代码如下:

#include  
#include  
#include  
#include  
#include  
#include  
#include  

int main() 
{ 
  int sockfd = -1; 
  int len = 0; 
  struct sockaddr_in address; 
  int result; 
  char ch = 'A'; 
  //创建流套接字 
  sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  //设置要连接的服务器的信息 
  address.sin_family = AF_INET;//使用网络套接字 
  address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址 
  address.sin_port = htons(9736);//服务器所监听的端口 
  len = sizeof(address); 
  //连接到服务器 
  result = connect(sockfd, (struct sockaddr*)&address, len); 

  if(result == -1) 
  { 
    perror("ops:client\n"); 
    exit(1); 
  } 
  //发送请求给服务器 
  write(sockfd, &ch, 1); 
  //从服务器获取数据 
  read(sockfd, &ch, 1); 
  printf("char form server = %c\n", ch); 
  close(sockfd); 
  exit(0); 
} 

运行结果如下:

在本例子中,我们启动了一个服务器程序和三个客户程序,从运行的结果来看,客户端发送给服务器程序的所有请求都得到了处理,即把A变成了B。对于服务器和客户程序之间使用的read和write系统调用跟使用命名管道时阻塞的read、write系统调用一样。例如客户程序调用read时,如果服务器程序没有向指定的客户程序的socket中写入信息,则read调用会一直阻塞。

七、流式套接字给我印象

给我的感觉是流式套接字很像命名管道,但是它却可以使不在同一台计算机而通过网络连接的不同计算机上的进程进行通信,功能真是非常的强大。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


推荐阅读
  • 本文介绍了如何使用iptables添加非对称的NAT规则段,以实现内网穿透和端口转发的功能。通过查阅相关文章,得出了解决方案,即当匹配的端口在映射端口的区间内时,可以成功进行端口转发。详细的操作步骤和命令示例也在文章中给出。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 概述H.323是由ITU制定的通信控制协议,用于在分组交换网中提供多媒体业务。呼叫控制是其中的重要组成部分,它可用来建立点到点的媒体会话和多点间媒体会议 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • UDP千兆以太网FPGA_verilog实现(四、代码前期准备UDP和IP协议构建)
    UDP:userDatagramprotocol用户数据报协议无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETFRFC76 ... [详细]
  • SQL Server 2008 到底需要使用哪些端口?
    SQLServer2008到底需要使用哪些端口?-下面就来介绍下SQLServer2008中使用的端口有哪些:  首先,最常用最常见的就是1433端口。这个是数据库引擎的端口,如果 ... [详细]
  • 三、寻找恶意IP并用iptables禁止掉找出恶意连接你的服务器80端口的IP,直接用iptables来drop掉它;这里建议写脚本来运行, ... [详细]
  • 1、概述首先和大家一起回顾一下Java消息服务,在我之前的博客《Java消息队列-JMS概述》中,我为大家分析了:然后在另一篇博客《Java消息队列-ActiveMq实战》中 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了VoLTE端到端业务详解|VoLTE用户注册流程相关的知识,希望对你有一定的参考价值。书籍来源:艾怀丽 ... [详细]
  • slmp协议和mc协议区别_TCP协议与UDP协议的区别
    TCP协议和UDP协议TCPIP协议是一个协议簇。里面包括很多协议的,UDP只是其中的一个,之所以命名为TCPIP协议,因 ... [详细]
author-avatar
孤l叶_991
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有