Linux网络基础

Posted 小小孩~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux网络基础相关的知识,希望对你有一定的参考价值。

TCP、UDP协议

UDP 协议通信程序的编写

UDP 协议:无连接、不可靠、基于数据报传输

两端通信流程:

套接字相关接口介绍

#include <sys/socket.h> 头文件

一、 创建套接字
int socket(int domain, int type, int protocol);
(1) domain:地址域类型(域间通信、ipv4通信、ipv6通信… 不同通信有不同的地址结构)

(2) type:套接字类型
SOCK_STREAM:流式套接字,提供字节流传输,默认协议是 TCP 协议
SOCK_DGRAM:数据报套接字,提供的是数据报传输,默认协议是 UDP 协议

(3) protocol:协议类型,默认使用 0,表示使用套接字类型对应的默认协议
IPPROTO_TCP:值为 6
IPPROTO_UDP:值为 17

返回值:成功返回一个套接字描述符,失败返回 -1

二、为套接字绑定地址信息
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
(1) sockfd:socket 返回的套接字描述符
(2) my_addr:要绑定的地址信息
但是不同地址域类型具有不同的地址结构

ipv4 地址域类型 2B;端口号 2B;IP地址 4B
ipv6 地址域类型 2B;端口号 4B;IP地址 4B

(3) addrlen:绑定地址信息的长度
返回值:成功返回 0 ,失败返回 -1

三、发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
(1) sockfd:socket 返回的套接字描述符
(2) buf:要发送的数据空间起始地址
(3) len:要发送的数据长度,从 buf 地址开始,发送 len 长度的数据
(4) flags:默认 0-阻塞发送(发送缓冲区数据满了则等待)
(5) dest_addr:对端地址信息,描述数据要发送给谁(设置地址信息)
(6) addrlen:对端地址信息长度
返回值:成功返回实际发送数据字节长度,失败返回 -1

四、接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
(1) sockfd:socket 返回的套接字描述符
(2) buf:空间起始位置,接收到的数据存放在 buf 空间中
(3) len:想要接收到的数据长度
(4) flags:默认 0-阻塞接收(socket 接收缓冲区中没有数据则阻塞,直到有数据)
(5) src_addr:接收数据的同时,需要知道数据是谁发的,(获取地址信息)输出参数,用于返回对端地址信息
(6) addrlen:地址信息长度,输入输出参数,表示想要接收的地址信息长度以及实际得到的地址信息长度
返回值:成功返回实际接收到的数据长度,失败返回 -1

五、关闭套接字,释放资源
int close(int fd);

字节序相关接口

注意 32 位数据转换接口与 16 位数据转换接口不可混用

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
主机字节序到网络字节序的转换

uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
网络字节序到主机字节序的转换

示例说明:

IP 地址转换接口

in_addr_t inet_addr(const char *cp); 将点分十进制IP地址转换为网络字节序整型IP地址

const char *inet_ntoa(struct in_addr in); 将网络字节序整型IP地址转换为点分十进制IP地址
inet_ntoa 接口,若返回的是一个局部变量(函数退出就会释放),这个函数返回的是静态变量地址


测试代码:

服务端:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 #include <arpa/inet.h>  //字节序转换接口头文件
  6 #include <sys/socket.h>  //套接字接口头文件
  7 #include <netinet/in.h>  //地址结构类型以及协议类型宏头文件
  8 
  9 int main(int argc,char* argv[])
 10 
 11   if(argc!=3)
 12     printf("./udp_ser 192.168.2.2 9000\\n");
 13     return -1;
 14   
 15   uint16_t port=atoi(argv[2]);   //端口信息,uint16 属于 ipv4 数据类型----包含有2字节16位数据 ,atoi 将字符串转换为整数
 16   char* ip=argv[1] ;  //ip 地址信息
 17 
 18   //1、创建套接字
 19   //int socket(int domain, int type, int protocol);
 20   int sockfd=socket(AF_INET ,SOCK_DGRAM,IPPROTO_UDP);                           
 21                //AF_INET 代表的是 ipv4 地址域类型,SOCK_DGRAM 表示数据报套接字-UDP,IPPROTO_UDP 表示 UDP 协议类型
 22 
 23   if(sockfd<0)
 24     perror("socket error!\\n");
 25     return -1;
 26   
 27 
 28   
 29   //2、为套接字绑定地址信息
 30   //int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);          
 31     
 32   struct sockaddr_in addr; //定义一个 IPV4 地址结构
 33   addr.sin_family=AF_INET;  //定义为 IPV4 地址域类型
 34   addr.sin_port=htons(port);  //ipv4 地址域端口为 uint16_t 对应 16 位----使用 htons 进行主机字节序端口到网络字节序端口的转换
 35   addr.sin_addr.s_addr=inet_addr(ip);  //将点分十进制字符串 IP 地址转换为整型IP地址
 36   socklen_t len=sizeof(struct sockaddr_in);   //计算地址信息长度
 37 
 38   int ret=bind(sockfd,(struct sockaddr*)&addr,len);    //传递地址信息需要进行类型强转
 39   if(ret<0)
 40     perror("bind error!\\n");  //套接字绑定地址信息失败
 41     return -1;
 42   
 43 
 44   //3、循环接收发送数据
 45   while(1)
 46     //接收信息
 47     //ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
 48     char buff[1024]=0;  //接收到的信息存放地址
 49     struct sockaddr_in peer;  //从哪里接收到的信息
 50     socklen_t len=sizeof(struct sockaddr_in);  //接受的数据长度
 51     
 52     ssize_t ret= recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&peer,&len);  //0-阻塞
 53     if(ret<0)
 54       perror("recvfrom error!\\n");                                              
 55       return -1;  
 56     
 57     
 58 
 59     char* peerip=inet_ntoa(peer.sin_addr);  //数据发送到哪里,将整形 IP 地址转换为点分十进制的 IP 地址
 60     uint16_t peerport=ntohs(peer.sin_port);   //ipv4 地址域类型为 uint16_t 含有16 位数字-->ntohs,将网络字节端口转换为主机字节序端口
 61 
 62     printf("client[%s : %d] say:%s",peerip,peerport,buff);
 63     
 64 
 65     //发送信息
 66     //ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
 67     char data[1024]=0 ;  //要发送的数据存放位置
 68     printf("server say: ");                                                     
 69     fflush(stdout);
 70     scanf("%s",data);
 71     
 72     ret=sendto(sockfd,data,strlen(data),0,(struct sockaddr*)&peer,len);  //0-阻塞
 73     if(ret<0)
 74       perror("sendto error!\\n");
 75       return -1;
 76     
 77 
 78   
 79   //关闭套接字
 80   close(sockfd);
 81 
 82   return 0;
 83 

进行绑定(bind)端口时候:
虚拟机绑定的是 ens33 处的网卡信息


云服务器绑定的是 etho 处的网卡信息

端口是一个 uint16_t 类型的数据,范围 0~65535
但是 0~1023 这些端口被一些知名服务使用,例如 ssh–22号,http–80号端口
因此在使用时候尽量使用 1024 以上的端口,防止端口冲突导致绑定失败。

对于服务端或客户端都会存在:
创建套接字、绑定地址(客户端不需要绑定)、发送数据、接收数据、关闭套接字,因此我们可以将套接字的一系列接口进行封装来使用:

  1 #include <iostream>
  2 #include<assert.h>
  3 #include<unistd.h>
  4 #include<string>
  5 #include <cassert>
  6 #include<sys/socket.h>
  7 #include<arpa/inet.h>  //字节序转换接口头文件
  8 #include<netinet/in.h>  //地址结构类型以及协议类型宏头文件
  9 
 10 //进行 UDP 接口的封装
 11 
 12 class UdpSocket
 13   private:
 14     int _sockfd;
 15   public:
 16     UdpSocket():_sockfd(-1) 
 17     ~UdpSocket() 
 18       Close();
 19     
 20 
 21     //创建套接字                                                                   
 22     bool Socket()
 23       _sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//定义为 IPV4 地址域,数据报传输(UDP),定义传输协议为 UDP 协议
 24       if(_sockfd<0)
 25         perror("socket error!\\n");
 26         return false;  
 27       
 28       return true;  //创建套接字成功
 29     
 30                                                                                    
 31     //给套接字绑定地址空间
 32     bool Bind(const std::string& ip,uint16_t port)
 33     
 34       //创建 ipv4 地址域结构 struct sockaddr_in 类型
 35       struct sockaddr_in addr;
 36       addr.sin_family=AF_INET;  //ipv4 地址域类型
 37       addr.sin_port=htons(port);  //将主机字节序转换为网络字节序---16位使用 htons       
 38       addr.sin_addr.s_addr=inet_addr(ip.c_str());  //将 IP 地址转换为整型 IP 
 39       socklen_t len=sizeof(struct sockaddr_in);
 40 
 41       int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
 42       if(ret<0)
 43         perror("bind error!\\n");
 44         return false;
 45       
 46       return true;
 47     
 48 
 49     //接收数据
 50     bool Recv(std::string& body,std::string* peer_ip = NULL,uint16_t* peer_port=NULL)
 51     
 52       struct sockaddr_in peer;
 53       socklen_t len=sizeof(struct sockaddr_in);
 54       char tmp[4096]=0;
 55       ssize_t ret=recvfrom(_sockfd,tmp,4096,0,(struct sockaddr*)&peer,&len);   //0-阻塞接收
 56       if(ret<0)
 57         perror("recvfrom error!\\n");                                               
 58         return false;
 59       
 60       if(peer_ip!=NULL)
 61         *peer_ip=inet_ntoa(peer.sin_addr);  //获取到源端IP信息,转换为点分十进制IP地址
 62       if(peer_port!=NULL)
 63         *peer_port=ntohs(peer.sin_port);  //将网络套接字转换为主机套接字
 64       body.assign(tmp,len);  //从 tmp 获取 len 长度字节放入到 body 中
 65       return true;
 66     
 67 
 68 
 69     //发送数据
 70     bool Send(const std::string& body,const std::string& peer_ip,uint16_t peer_port    )
 71     
 72       struct sockaddr_in addr;
 73       addr.sin_family=AF_INET;
 74       addr.sin_port=htons(peer_port);  //将点云十进制 IP 转换为整型 IP
 75       addr.sin_addr.s_addr=inet_addr(peer_ip.c_str());  //将主机字节序转换为网络字节序
 76       socklen_t len=sizeof(struct sockaddr_in);
 77                                                                                    
 78       ssize_t ret=sendto(_sockfd,body.c_str(),body.size(),0,(struct sockaddr*)&addr,len);
 79       if(ret<0)
 80         perror("sendto error!\\n");
 81         return false;
 82       
 83       return true;
 84     
 85 
 86     //关闭套接字
 87     bool Close()
 88     
 89       if(_sockfd!=-1)
 90         close(_sockfd);
 91         _sockfd=-1;
 92       
 93       return true;
 94     
 95 ;

客户端-服务端代码可以参考:
添加链接描述
添加链接描述

运行结果显示:

网络通信程序进行通信时候有可能是跨主机的,因此会涉及到防火墙设置:

(虚拟机)需要先停用防火墙才能进行通信
1、sudo systemctl stop firewalld 停止防火墙服务
2、sudo systemctl diable firewalld 禁用防火墙(下次开始依然不会重启)
虚拟机只能实现与自己电脑、或虚拟机内部通信,无法实现跨主机(因为虚拟机IP是私有地址且对外隐藏)
NAT 地址转换技术----将私网内的主机对外发送的数据的源端地址进行替换为对外地址

(云服务器)登录云服务器网站,进行安全策略组设置,开通指定要访问的接口,才能实现对外访问

TCP 协议通信程序的编写

TCP :面向连接、可靠传输、面向字节流的传输

因为 TCP 是面向连接的,在进行通信之前必须先建立连接(一对一),因此在 TCP 通信中不限定必须是客户端先进行发送数据

TCP 通信程序中:
客户端向服务器发送一个连接建立请求,服务端处于监听状态,则会对这个连接建立请求进行处理----> (1)为这个新连接请求,创建一个套接字结构体;(2)为这个新的套接字,描述完整的五元组信息;往后的数据通信就由这个套接字进行通信

一个服务器上有多少客户端想要建立连接,服务端就要创建多少个套接字(源端IP及端口都是一样的);而最早的服务端创建监听套接字则只负责新连接请求处理,不负责数据的通信

服务端会为每个客户端都创建一个新的套接字,负责与这个客户端进行数据通信,但是想要通过这个套接字与客户端进行通信就必须知道这个套接字的描述符

通信流程:

套接字接口介绍

一、创建套接字
int socket(int domain, int type, int protocol);
(1)domain:地址域类型-----ipv4 通信 AF_INET
(2)type:套接字类型–字节流传输 – SOCK_STREAM
(3)protocol:协议类型: IPPROTO_TCP

二、建立连接
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
(1)sockfd:socket 返回的套接字描述符
(2)my_addr:要绑定的地址信息
(3)addrlen:要绑定的地址信息长度
返回值:成功返回 0,失败返回 -1

三、开始监听
int listen(int socket, int backlog);
(1)socket:创建套接字返回的监听套接字描述符
(2)backlog:同一时刻最大并发连接数(限制同一时间有多少个客户端连接请求能够被处理-----否则会导致系统崩溃(连续创建多个套接字导致系统资源耗尽))
返回值:成功返回 0 ,失败返回 -1

-内核中每个监听套接字都有一个对应新连接的socket队列:半连接队列 / 已完成连接队列 (半连接队列被放满,当在有新的连接需要建立时会被直接丢弃)

-listen 函数第二个参数 backlog 限制的就是队列中节点数量 = backlog + 1

泛洪攻击------SYN cookies (自行调研)

四、向服务端发送连接建立请求(客户端使用)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
(1)sockfd:套接字描述符
(2)addr:服务端地址信息
(3)addrlen:地址长度

五、获取新建连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
从内核 sockfd 指定的监听套接字对应的已完成连接队列中,取出一个 socket 并返回其描述符,通过 addr 参数返回值可以知道具体连接请求来源于哪个客户端
(1)sockfd:套接字描述符,是我们创建的套接字 sockfd
(2)addr:accept 接收到的填充客户端地址----输出参数
(3)addrlen:地址信息长度–输入输出参数,用于指定想要获取的地址长度以及返回实际地址信息长度
返回值:成功返回新连接的套接字描述符,出错返回 -1

六、收发数据
int send(int sockfd, const void *msg, size_t len, int flags);
sockfd 是 accept 函数中返回的新建连接的 sockfd
相较于 sendto 不需要指定 IP 和端口信息
返回值:成功返回实际发送数据的长度,失败返回 -1

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd 是 accept 函数中返回的新建连接的 sockfd
相较于 recvfrom 不需要获取 IP 和端口信息
返回值:成功返回实际发送的字节长度,出错返回 -1 ,连接断开返回 0

recv 返回值为 0 ,主要是告诉程序员连接断开了

TCP 是面向连接的,一旦连接断开将无法实现通信(对方关闭了连接/网络出错)

七、关闭套接字
int close(int fd);

测试代码:

对 TCP 相关接口进行封装

  1 #include<iostream>
  2 #include<string>
  3 #include<stdio.h>                                                      
  4 #include<unistd.h>
  5 #include <sys/socket.h>
  6 #include <arpa/inet.h>
  7 #include <netinet/in.h>
  8 
  9 #define BACKLOG 1024    //宏定义:同一时刻最大客户端建立连接数
 10 
 11 //封装一个 TCP 接口
 12 class TcpSocket
 13   private:
 14     int _sockfd;
 15   public:
 16     TcpSocket():_sockfd(-1) 
 17     ~TcpSocket()
 18         Close();
 19         _sockfd=-1;
 20     
 21 
 22     //创建套接字:TCP 协议
 23     bool Socket()
 24         //SOCK_STREAM :字节流传输   ,IPPROTO_TCP :表示使用 TCP 协议
 25       _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 26       if(_sockfd<0)
 27         perror("socket error!\\n");
 28         return false;
 29       
 30       return true;
 31     
 32     //绑定端口
 33     bool Bind(const std::string &ip,uint16_t port)
 34       //建立 ipv4 地址结构
 35       struct sockaddr_in addr;  //ipv4 地址结构
 36       addr.sin_family=AF_INET;  //ipv4 地址域                          
 37       addr.sin_port=htons(port);   //将主机套接字转换为网络套接字
 38       addr.sin_addr.s_addr=inet_addr(ip.c_str());  //将地址信息转化为整型 IP 地址
 39       socklen_t len=sizeof(struct sockaddr_in);
 40 
 41       int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
 42       if(ret<0)
 43         perror("bind error!\\n");
 44         return false;
 45       
 46       return true;
 47     
 48 
 49     //开始监听
 50     bool Listen(int backlog = BACKLOG)
 51     
 52       int ret=listen(_sockfd,backlog);
 53       if(ret<0)
 54         perror("listen error!\\n");                                     
 55         return false;
 56       
 57       return true;
 58     
 59 
 60     //建立连接:客户端申请向服务端进行连接(只要客户端需要该接口)
 61     bool Connect(const std::string& srvip,uint16_t srvport)
 62     
 63       struct sockaddr_in addr;
 64       addr.sin_family=AF_INET;
 65       addr.sin_port=htons(srvport); //主机字节序转换为网络字节序
 66       addr.sin_addr.s_addr=inet_addr(srvip.c_str());  //将地址信息转化为整型 IP 地址
 67       socklen_t len=sizeof(struct sockaddr_in);
 68 
 69       int ret=connect(_sockfd,(struct sockaddr*)&addr,len);
 70       if(ret<0)
 71         perror("connect error!\\n");
 72         return false;
 73       
 74       return true;
 75     
 76 
 77     //接收连接,获取新建连接的客户端地址信息
 78     bool Accept(TcpSocket* new_sock,std::string* cli_ip=NULL,uint16_t*cli_port=NULL)                                                         
 79     
 80       struct sockaddr_in addr;
 81       socklen_t len=sizeof(struct sockaddr_in);
 82       int newfd=accept(_sockfd,(struct sockaddr*)&addr,&len);
 83       if(newfd<0)
 84         perror("accept error!\\n");
 85         return false;
 86       
 87       new_sock->_sockfd=newfd;       //新连接的套接字描述符
 88       if(cli_ip != NULL)
 89         *cli_ip=inet_ntoa(addr.sin_addr); //将获取到的客户端 IP 地址转换为整型
 90       if(cli_port!=NULL)
 91         *cli_port=ntohs(addr.sin_port);//将客户端端口从网络套接字 IP 转换为主机套接字(因为 ipv4 地址域类型为 uint16 含有两字节因此使用 ntohs    )
 92       return true;
 93     
 94 
 95     //发送数据
 96     bool Send(const std::string& body)
 97     
 98       ssize_t ret=send(_sockfd,body.c_str(),body.size(),0);  //0-阻塞等待,此处 _sockfd 为已经建立连接的套接字描述符
 99       if(ret<0)                                                       
100         perror("send error!\\n");
101         return false;
102       
103       return true;
104     
105 
106 
107     //接收数据
108     bool Recv(std::string* body)
109     
110       char tmp[1024]=0;
111       //recv 返回值大于 0;等于 0(表示断开连接);小于0(表示出错)
112       ssize_t ret =recv(_sockfd,tmp,1023,0);  //0-阻塞等待  ,此处 _sockfd 为已经建立连接的套接字描述符
113       if(ret<0)
114         perror("recv error!\\n");
115         return false;
116       
117       else if(ret==0)        //连接断开
118         printf("connect shutdown!\\n");
119         return false;
120                                                                       
121       body->assign(tmp,ret);  //从 tmp 截取 ret 长度数据放到 body 
122       return true;
123     
124     
125     //关闭套接字
126     bool Close()
127     
128       if(_sockfd!=-1)
129         close(_sockfd);
130         _sockfd=-1;
131       
132       return true;
133     
134 ;

在客户端与服务端我们进行调用所封装的 TcpSocket 类来实现套接字创建、建立连接、接收连接、收发数据、关闭套接字信息等。

但是在代码运行过程中我们会发现一些问题:

问题一


服务端 TcpSocket new_sock 是一个局部变量,while 循环一次之后就会被释放析构,因此在服务端接收数据时候会发现 recv 返回值为 0 - 连接断开(connect shutdown 信息提示)

当我们将封装好的 TcpSocket 类内析构函数中将关闭套接字接口去掉之后,又发现一个新问题-------> 客户端只能与服务端建立一次通信:

这主要是因为 TcpSocket new_sock 是一个局部变量,每一次循环进入之后都会创建一个新套接字,导致只能接受新连接(新建立的客户端的通信)的一次通信,因此导致一个客户端无法与服务端建立连续的通信------------------那么,我们考虑能否将收发数据变为循环进行的,从而实现同一个客户端与服务端的连续通信

问题二

在服务端内部收发数据部分添加 while 循环时发现可以建立多次通信,但是多个客户端运行时只有一个客户端能够与服务器建立通信,而其他客户端不能进行与服务器的通信

而当我们关闭第一个客户端的连接之后,发现服务端卡死:

这主要是因为,我们在服务端循环收发数据时候使用的是 continue ,当接收/发送数据失败时候,跳出当前循环等待下一次接收/发送数据,从而导致了服务端卡死,因此我们需要将 continue 变为 break 跳出本次循环,结束当前的数据收发:

本质原因:

多执行流要进行多任务处理有两种方案:
多进程 & 多线程
多进程:安全、健壮
多线程:通信灵活、消耗小

多进程实现多执行流

我们采用多进程来解决以上问题:
主进程只负责一件事----->获取新连接,获取成功则创建一个新的子进程,让子进程来实现与客户端的通信

但是要考虑子进程退出形成僵尸进程,因此需要忽略子进程退出信号:

此时,多个客户端可以完成与服务端的正常通信:

注意

在创建子进程之后,要考虑的第一个问题就是僵尸进程—子进程退出,为了保存退出返回值而导致子进程资源没有完全释放,因此我们进行了一个信号的忽略处理 signal(SIGCHLD,SIG_IGN)

同时还需考虑一个问题:子进程创建 fork() 之后会导致父子进程代码共享数据独有,子进程来负责与客户端的通信,而父进程负责创建新建连接,但是在父进程这边,只需要创建新建连接获取新建连接的套接字描述符,在后期父进程并未使用该套接字描述符,因此会存在一个内存泄漏问题(由于之前我们去除掉了析构函数中的套接字关闭接口),因此在子进程进行收发数据失败之后只关闭了子进程中的套接字描述符,而父进程中没有关闭
所以,在父进程的运行中,我们需要调用套接字关闭接口来避免内存泄漏

客户端-服务端代码实现:
添加链接描述
添加链接描述

多线程实现多执行流

将服务端的数据收发处理交给不同的线程来进行处理,因此在完成一个新建连接之后,我们需要进行线程的创建,成功创建则进行数据收发的处理

服务端代码:
(在这段代码中我们采用的是类型强制转换,因此运行时会有一个警告)
添加链接描述

改进:
使用指针类型参数实现:

添加链接描述

在外面运行程序时,常会有一个提示说绑定地址失败:

主要是因为当前这个端口被占用

netstat -anptu:

查看当前主机上所有网络连接状态
a:all 所有连接信息
n : 以 IP 地址和端口号显示,而不要用服务名称来显示—> 127.0.0.1 – localhost ,22 – ssh 端口
p:显示连接对应的进程 ID 和 名称
t:tcp 套接字信息
u:udp 套接字信息

欢迎点赞留言鸭!!

linux网络配置

Linux怎么配置静态IP地址

Linux如何设置网络地址参数——基础网络设置

前言:之前我们已经分享了解了Linux系统的基本管理命令和技巧,为进一步学习Linux网络服务打下了基础,接下来让我们一起了解Linux系统的网络设置、文件服务、域名解析等在网络服务器方面的应用。

一、查看网络配置

确保网络配置的正确性及网络连接的畅通是Linux系统作为服务器应用的基础,查看及测试网络配置是管理Linux网络服务的第一步。

1.ifconfig——查看网络配置

1) 查看所有活动网络接口的信息

执行 ifconfig 或ip addr或ip a命令,都可以显示当前主机中已启用(活动)的网络接口信息。

示例:(注:图示中为RHEL6版本,7版本中网卡名称为ens33)

2) 查看指定网络接口信息

格式:ifconfig 网络接口名

图示:(7版本网络接口(网卡的名称)为ens开头)

如上图所示,还可以通过TX、RX等信息了解到通过该网络接口发送和接收的数据包个数,流量等跟多属性。

2.hostname命令

在Linux系统中,相当一部分网络服务都会通过主机名来识别本机,如果主机名配置不当,可能会导致程序功能出现故障。

1) 查看主机名

使用hostname命令就可以查看当前主机的主机名,不添加任何选项参数。

示例:

2) 临时更改主机名

命令格式:

示例:

注:这种方法只是临时的更改主机名,重启后将失效。

3) 永久更改主机名

a. 修改配置文件

RHEL6和7的配置文件存放路径不相同,修改配置文件中的主机名,重启就可永久更改主机名。

RHEL6主机名配置文件路径为:/etc/sysconfig/network

RHEL7主机名配置文件路径为:/etc/hostname

示例:(示例为RHEL6的修改,7也一样,只是文件路径不一样)

b. 使用命令修改(这种方法只适用于RHEL7或者CentOS7之后)

命令格式:

使用该命令更改后,更改后的主机名就自动写入了配置文件中,所以可以永久更改主机名,其实就是修改了配置文件。

3.route命令

直接执行route命令可以查看当前主机中的路由表信息,若结合“-n”选项使用,可以将路由记录中的地址显示为数字形式,这可以跳过解析主机名的过程,在路由表条目较多的情况下能够加快执行速度。

示例:

Destination列对应的是目标网段的地址,Gateway列对应的是吓一跳路由器的地址,Iface列对应的是发送数据的网络接口。当目标网段为“default”是,表示此行是默认网关记录,当吓一跳为“*”是,表示目标网段是与本机直接相连的。

4.netstat命令——查看系统的网络连接状态等

netstat命令是了解网络状态及排除网络服务故障的有效工具。

命令格式:

常用选项:

-a:显示所有活动连接(包括监听、非监听状态的服务端口)

-n:以数字形式显示

-p:显示相关的进程信息

-t:查看 TCP 协议相关信息

-u:查看UDP协议相关信息

-r:显示路由表信息

-l:显示处于监听(listening)状态的网络连接及端口信息

通常使用“-anput”组合选项,结合管道使用“grep”命令,来查看一些服务的端口是否开启。

示例:

Tcp21为ftp服务的端口

二、测试网络连接

1.ping命令——测试网络连通性

命令格式:

常用选项:

-c<完成次数>:设置完成要求回应的次数

-i<间隔秒数>:指定收发信息的间隔时间

-q:不显示指令执行过程,开头和结尾的相关信息除外

-s<数据包大小>:设置数据包的大小

-t<存活数值>:设置存活数值TTL的大小

-v:详细显示指令的执行过程

示例:

若返回“Destination Host Unreachable”的反馈信息,则表示目标主机不可达,可能目标地址不存在或主机已关闭;返回“Network is unreachable”的反馈信息,则表示没有可用的路由记录(如默认网关),无法到达目标主机所在的网络;返回“Request timeout”的反馈信息,表示与目标主机间的连接超时(数据包缓慢或丢失),若有严格的防火墙限制,也可能返回此信息。

2.traceroute命令——跟踪数据包的路由途径

使用traceroute命令可以测试从当前主机到目的主机之间经过的网络节点,并显示各中间结点的连接状态(响应时间)。对于无法响应的节点,连接状态将显示为“*”。

命令格式:

示例:

在网络测试与排错的过程中,通常会先使用ping命令测试与主机的网络连接,如果发现网络有故障,再使用traceroute命令跟踪查看是在哪个中间结点存在故障。

3.nslookup命令——测试DNS域名解析

nslookup是用来测试(DNS)域名解析的专用工具。(DNS服务后面再详细讲解,通俗的说就是将域名解析为ip地址的一个服务)

命令格式:

示例:

若成功反馈要查询域名的IP地址,则表示域名解析没有问题;若出现“...... no servers could be reached”的信息,表示不能连接到指定的DNS服务器;若出现“...... cant’t find xxx.yyy.zzz:NXDOMAIN”的信息,表示要查询的域名不存在。

三、设置网络地址参数

设置网络参数的方法:

?临时配置 —— 使用命令调整网络参数
简单、快速,可直接修改运行中的网络参数

一般只适合在调试网络的过程中使用

系统重启以后,所做的修改将会失效

?永久配置 —— 通过配置文件修改网络参数
修改各项网络参数的配置文件

适合对服务器设置固定参数时使用

需要重载网络服务或者重启以后才会生效

1.临时配置——使用网络配置命令(注:RHEL6中网络接口的名称为eth,RHEL7中为ens)

1)使用ifconfig命令修改网卡的地址、状态

ifconfig命令不仅可以用于查看网卡配置,还可以修改网卡的ip地址,子网掩码,也可以绑定网络接口、激活或停用网络接口

a. 修改网卡的ip地址(临时修改)

命令格式:

示例:

b. 禁用或者重新激活网卡

命令格式:

示例:

c. 设置虚拟网络接口(相当于一块网卡配置多个IP地址)

命令格式:

示例:

可以根据需要添加更多的虚拟接口,如“eth0:1”“eth0:2”等

2)使用route命令添加、删除静态路由记录

?删除路由表中的默认网关记录
命令格式:route del default gw IP地址

?向路由表中添加默认网关记录
命令格式:route add default gw IP地址

?添加到指定网段的路由记录
命令格式:route add -net 网段地址 gw IP地址

?删除到指定网段的路由记录
命令格式:router del -net 网段地址

2.永久配置——修改网络配置文件

1)网络接口配置文件

网络接口的配置文件默认位于目录“/etc/sysconfig/network-scripts/”中,文件名格式为:“ifcfg-XXX”,其中“XXX”是网络接口的名称。例如:RHEL6中网卡eth0的配置文件是“ifcfg-eth0”,而RHEL7中网卡ens33的配置文件是“ifcfg-ens33”。

在网卡的配置文件中,可以看到静态IP地址的部分内容如下图所示:

上述个配置项的含义及作用:(图示为RHEL6中的配置文件,7中也差不多,换汤不换药,修改的都差不多)

?DEVICE:设置网络接口的名称

?ONBOOT:设置网络接口是否在Linux系统启动时激活

?BOOTPROTO:设置网络接口的配置方式,值为static时表示使用静态ip地址,为dhcp时表示通过dhcp的方式动态获取ip地址

?IPADDR:设置网络接口的ip地址

?NETMASK:设置网络接口的子网掩码

?GATEWAY:设置网络接口的默认网关地址
2)重启 network 网络服务

当修改了网络接口的配置文件以后,若要使新的配置生效,可以重启network服务或者重启主机或者禁用、启用网络接口。

示例:

?RHEL6中重启network服务:service network restart

?RHEL7中重启network服务:systemctl restart network
注:这是我在做实验时候的一个经验:RHEL6修改完网卡配置重启后,ip地址仍然没有改过来,这时候我们经常会删除“/etc/udev/rules.d/70-persistent-net.rules”这个文件。RHEL7不用管,RHEL7特别好改,RHEL6改的时候特别难受。(个人提示,不求认同)

3)域名解析配置文件

a.指定为本机提供DNS解析的服务器地址

/etc/resolv.conf文件中记录了本机默认使用的DNS服务器的地址信息,对该文件所做的修改将会立刻生效。Linux系统中最多可以指定3个(第3个以后将被忽略)不同的DNS服务器地址,优先使用第1个DNS服务器。

示例:

其中“search localdomain”用来设置默认的搜索域(域名后缀)。例如,当访问主机“localhost”时,就相当于访问“localhost.localdomain”。

b.本地主机映射文件

/etc/hosts文件中记录着一份主机名与ip地址的映射关系表,一般用来保存经常访问的主机信息。当访问一个未知的域名时,先查找该文件中是否有相应的映射记录,如果找不到在去向DNS服务器查询。

hosts 文件和 DNS 服务器的比较

?默认情况下,系统首先从 hosts 文件查找解析记录

?hosts 文件只对当前的主机有效

?hosts 文件可减少 DNS 查询过程,从而加快访问速度

以上是关于Linux网络基础的主要内容,如果未能解决你的问题,请参考以下文章

Linux网络编程必学!——Linux_网络编程_UDP

Linux网络编程必学!——Linux_网络编程_UDP

Linux从青铜到王者第十七篇:Linux网络基础第二篇之UDP协议

Linux----网络传输层UDP/TCP

Linux内核网络udp数据包发送——UDP协议层分析

Linux内核网络udp数据包发送——UDP协议层分析