热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

linux网络编程

网络编程TCPIP网络模型数据封装TCPIP协议族TCPIP实际上是一个协同工作的通信家族,为网络数据通信提供通路。TCPIP协议族大体分为三部分:Internet协议(IP)传输

网络编程

TCP/IP

网络模型

linux-网络编程

linux-网络编程

数据封装

linux-网络编程

TCP/IP协议族

TCP/IP实际上是一个协同工作的通信家族,为网络数据通信提供通路。TCP/IP协议族大体分为三部分:

  • Internet协议(IP)

  • 传输控制协议(TCP)和用户数据报协议(UDP)

  • 处于TCP和UDP之上的一组应用协议。包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等

网络层

第一部分称为网络层。主要包括Internet协议(IP)、网际控制报文协议(ICMP)和地址解析协议(ARP):

  • Internet协议(IP)

    该协议被设计成互联分组交换通信网,以形成一个网际通信环境。它负责在源主机和目的主机之间传输来自较高层软件的称为数据报文的数据块,它在源和目的地之间提供非连接型传递服务。

  • 网际控制报文协议(ICMP)

    它实际上不是IP层部分,但直接同IP层一起工作,报告网络上的某些出错情况。允许网际路由器传输差错信息或测试报文。

  • 地址解析协议(ARP)

    ARP实际上不是网络层部分,它处于IP和数据链路层之间,它是在32位地址和48位物理地址之间执行翻译的协议。

传输层协议

第二部分是传输层协议,包括传输控制协议和用户数据报文协议。

  • 传输控制协议(TCP):

    该协议对建立网络用户进程之间的对话负责,它确保进程之间的可靠通信,所提供的功能如下:

    1. 监听输入对话建立请求

    2. 请求另一网络站点对话

    3. 可靠的发送和接受数据

    4. 适度的关闭对话

  • 用户数据报文协议(UDP):

    UDP提供不可靠的非连接型传输层服务,它允许在源和目的地之间传送数据,而不必在传送数据之前建立对话。它主要用于那些非连接型的应用程序,如:视频点播。

应用协议

这部分主要包括Telnet,文件传送协议(FTP和TFTP),简单文件传送协议(SMTP)和域名服务(DNS)等协议

IP协议

IP主要有以下四个主要功能:

  • 数据传送

  • 寻址

  • 路由选择

  • 数据报文的分段

IP的主要目的是为数据输入/输出网络提供基本算法,为高层协议提供无连接的传送服务。这意味着在IP将数据递交给接收点以前不在传输站点和接收站点之间建立对话。它只是封装和传递数据,但不向发送者或接收者报告包的状态,不处理所遇到的故障。

IP包由IP协议头与协议数据两部分构成。

linux-网络编程

TCP协议

TCP是重要的传输层协议,目的是允许数据同网络上的其他节点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输。

  • TCP协议具有严格的内装差错检验算法确保数据的完整性

  • TCP是面向字节的顺序协议,这意味着包内的每个字节被分配一个顺序编号,并分配给每包一个顺序编号。

TCP协议头

linux-网络编程

UDP协议

UDP也是传输层协议,它是无连接的,不可靠的传输服务。当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文。由于它执行功能时具有较低的开销,因而执行速度比TCP快。

linux-网络编程

Linux网络编程

Socket

Linux中的网络编程通过Socket(套接字)接口实现,Socket是一种文件描述符。

类型

套接字socket有三种类型:

  • 流式套接字(SOCK_STREAM)

    流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP保证了数据传输的正确性和顺序性。

  • 数据报套接字(SOCK_DGRAM)

    数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错,它使用数据报协议UDP

  • 原始套接字

    原始套接字允许对底层协议如IP或ICMP直接访问,主要用于新的网络协议的测试等。

地址结构

struct sockaddr
{
    u_short sa_family;
    char as_data[14];
}

sa_family:地址族,采用“AF_xxx”的形式,如AF_INET

sa_data:14字节的特定协议地址

struct sockaddr_in
{
    short int sin_family;//Internet地址族
    unsigned short int sin_port;//端口号
    struct in_addr sin_addr;//IP地址
    unsigned char sin_zero[8];//填0
}

编程中一般并不直接针对sockaddr数据结构操作,而是使用与sockaddr等价的sockaddr_in数据结构

struct in_addr
{
    unsigned long s_addr;
}

s_addr:32位的地址

地址转换

IP地址通常是由数字加点(192.168.0.1)的形式表示,而在struct in_addr中使用的是IP地址是由32位的整数表示的,为了转换我们可以使用下面两个函数:

int inet_aton(const char *cp, struct in_addr *inp)
char *inet_ntoa(stuct in_addr in)

函数中a表示ascii n表示network。第一个函数表示将a.b.c.d形式的IP转换为32位的IP,存储在inp指针里面。第二个是将32位IP转换为a.b.c.d的格式。

字节序转换

网络传输的数据顺序是统一的,当内部字节存储顺序和网络字节顺序不同时,就一定要进行转换。

主要分为小端字节序和大端字节序

网络字节顺序时TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序。

htons

把unsigned short类型从主机序转换到网络序

htonl

把unsigned long类型从主机序转换到网络序

ntohs

把unsigned short类型从网络序转换到主机序

ntohl

把unsigned long类型从网络序转换到主机序

IP与主机名

在网络上标识一台机器可以用IP,也可以使用主机名

struct hostent *gethostbyname(const char *hostname)

struct hostent
{
    char *h_name;//主机的正式名称
    char *h_aliases;//主机的别名
    int h_addrtype;//主机的地址类型 AF_INET
    int h_length; //主机的地址长度
    char **h_addr_list;//主机的IP地址列表
}

#define h_addr h_addr_list[0]//主机的第一个IP地址

函数

进行Socket编程的常用函数有:

  • socket

    创建一个socket

  • bind

    用于绑定IP地址和端口号到socket

  • connect

    该函数用于绑定之后的client端,与服务器建立连接。

操作函数

  • listen

    设置能处理的最大连接要求,listen()并未开始接收连线,只是设置socket为listen模式

  • accept

    用来接受socket连接

  • send

    发送数据

  • recv

    接收数据

基于TCP-服务器

  1. 创建一个socket,用函数socket()

  2. 绑定IP地址、端口信息到socket上,用函数bind()

  3. 设置允许的最大连接数,用函数listen()

  4. 接收客户端上来的连接,用函数accept()

  5. 收发数据,用函数send()和recv(),或者read()和write()

  6. 关闭网络连接

基于TCP-客户端

  1. 创建一个socket,用函数socket()

  2. 设置要连接的对方的IP地址和端口等属性

  3. 连接服务器,用函数connect()

  4. 收发数据,用函数send()和recv(),或者read()和write()

  5. 关闭网络连接

linux-网络编程

基于UDP-服务器

  1. 创建一个socket,用函数socket()

  2. 绑定IP地址、端口等信息到socket上,用函数bind()

  3. 循环接收数据,用函数recvfrom()

  4. 关闭网络函数

基于UDP-客户端

  1. 创建一个socket,用函数socket()

  2. 绑定IP地址、端口等信息到socket上,用函数bind()

  3. 设置对方的IP地址和端口等属性

  4. 发送数据,用函数sendto()

  5. 关闭网络连接

linux-网络编程

服务器模型

循环服务器:服务器在同一个时刻只可以响应一个客户端的请求。

并发服务器:服务器在同一个时刻可以响应多个客户端的请求。

UDP循环服务器

UDP循环服务器的实现方法:UDP服务器每次从套接字上读取一个客户端的请求->处理->然后将结果返回给客户机。

socket(...)
bind(...)
while(1)
{
    recvfrom(...);
    process(...);
    sendto(...);
}

因为UDP是非面向连接的,没有一个客户端可以老是占住服务端,服务器对于每一个客户机的请求总是能够满足。

TCP循环服务器

TCP服务器接收一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。算法如下:

socket(...);
bind(...);
listen(...);
while(1)
{
    accept(...);
    process(...);
    close(...);
}

TCP循环服务器一次只能处理一次客户端的请求。只有在这个客户的所有请求都满足后,服务器才可以继续后面的请求。这样如果有一个客户端占住服务器不放时,其他的客户机都不能工作了,因此,TCP服务器一般很少用循环服务器模型的。

TCP并发服务器

并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是由服务器创建一个子进程来处理。算法如下:

socket(...);
bind(...);
listen(...);
while(1)
{
    accept(...);
    if(fork(..) == 0)
    {
        process(...);
        close(...);
        exit(...);
    }
    close(...);
}

TCP并发服务器可以解决TCP循环服务器客户机独占服务器的情况。但同时也带来了问题:为了响应客户的请求,服务器要创建子进程来处理,而创建子进程是一种非常消耗资源的操作。

阻塞复用I/O

阻塞函数在完成其指定的任务以前不允许程序继续向下执行。例如:当服务器运行到accept语句时,而没有客户请求连接,服务器就会停止在accept语句上等待连接请求的到来。这种情况称为阻塞,而非阻塞操作则可以立即完成。例如,如果希望服务器仅仅检查是否有客户等待连接,有就接受连接,否则就继续做其他事情,则可以通过使用select系统调用来实现。除此之外select还可以同时监视多个套接字。

int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct *timeout)

maxfd:文件描述符的范围,比待检的最大文件描述符大1

readfds:被读监控的文件描述符集

writefds:被写监控的文件描述符集

exceptfds:被异常监控的文件描述符集

timeout:定时器

timeout取不同的值,该调用有不同的表现:

  • timeout值为0,不管是否文件满足要求,都立刻返回,无文件满足要求返回0,有文件满足要求返回一个正值。

  • timeout为NULL,select将阻塞进程,直到某个文件满足要求

  • timeout值为正整数,就是等待的最长时间,即select在timeout时间内阻塞进程。

select调用返回时,返回值有如下情况:

  1. 正常情况下返回满足要求的文件描述符个数;

  2. 经过了timeout等待后仍无文件满足要求,返回值为0

  3. 如果select被某个信号中断,它将返回-1并设置errno为EINTR

  4. 如果出错,返回-1并设置相应的errno

使用:

  1. 设置要监控的文件

  2. 调用select开始监控

  3. 判断文件是否发生变换

系统提供了4个宏对描述符集进行操作:

#include 
void FD_SET(int fd, fd_set *fdset)
void FD_CLR(int fd, fd_set *fdset)
void FD_ZERO(fd_set *fdset)
void FD_ISSET(int fd, fd_set *fdset)

宏FD_SET将文件描述符fd添加到文件描述符集fdset中;

宏FD_CLR从文件描述符集fdset中清除文件描述符fd;

宏FD_ZERO清空文件描述符集fdset;

在调用select后使用FD_ISSET来检测文件描述符fdset中的文件fd发生了变换。

FD_ZERO(&fds);
sock1 = socket(...);
sock2 = socket(...);
bind(sock1...);
bind(sock2...);
listen(sock1, ...);
listen(sock2, ...);
FD_SET(sock1, &fds);//设置描述符
FD_SET(sock2, &fds);//设置描述符
maxfdp = (sock1 > sock2 ? sock1 : sock2) + 1;
switch(select(maxfdp, &fds, NULL, NULL, &timeout))
case -1:
    exit(1);//select错误, 退出程序
case 0:
    break;
default:
    if(FD_ISSET(sock1, &fds))//测试sock1是否可读
    accept(sock1, ...)    

推荐阅读
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Python操作MySQL(pymysql模块)详解及示例代码
    本文介绍了使用Python操作MySQL数据库的方法,详细讲解了pymysql模块的安装和连接MySQL数据库的步骤,并提供了示例代码。内容涵盖了创建表、插入数据、查询数据等操作,帮助读者快速掌握Python操作MySQL的技巧。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
author-avatar
mobiledu2502887507
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有