Linux网络编程

简介: Linux网络编程

Linux网络编程

TCP/IP与OSI

网络互联促成了TCP/IP协议的产生:

  • TCP协议分成两个不同的协议:
  • 用来检测网络传输差错的传输控制协议TCP
  • 专门负责对不同网络进行互联的互联网协议IP
  • 从此,TCP/IP协议产生。

网络体系结构:

  • 网络采用分而治之的方法设计,将网络的功能划分成不同的模块,以分层的形式有机组合在一起。
  • 每层实现不同的功能,其内部实现方法对外部其他层次来说都是透明的。每层向上层提供服务。同时使用下层提供的服务。
  • 网络体系结构即指网络的层次结构和每层所使用协议的集合。
  • 两类非常重要的体系结构:OSI与TCP/IP

OSI模型:

  • 应用层
  • 表示层
  • 会话层
  • 传输层
  • 网络层
  • 数据链路层
  • 物理层

TCP模型:

  • 应用层(FTP、HTTP、DNS、SMTP)----应用部分----
  • 传输层(TCP、UDP)------Linux内核部分-----
  • 网络层(IP、ICMP、IGMP)
  • 网络接口和物理层。(以太网、令牌环网、FDDI等)

socket编程基础

流式套接字(SOCK_STREAM):唯一对应着TCP

  • 提供了一个面向连接、可靠的数据传输服务、数据无差错、无重复的发送和接收。内设置流量控制。

数据包套接字(SOCK_DGRAM):唯一对应着UDP

  • 提供无连接服务,数据包以独立数据包的形式发送,不提供无差错保证。数据可能会丢失重复,顺序发送,但可能会乱序接收。

原始套接字(SOCK_RAW):对应着多个协议,发送穿透了传输层

  • 可以对较低层次协议,如IP、ICMP直接访问。

IP地址

IP地址是Internet中主机标志。

  • IP地址分为IPV4和IPV6。IPV4采用32位的整数表示。IPV6采用128位整数表示。
  • mobileIPV6:local IP(本地注册IP)、roam IP(漫游IP)

IPV4地址

  • 点分形式:192.168.0.246
  • 32位整数

特殊的IP地址

  • 局域网的IP:192.XXX.XXX.XXX、10.xxx。xxx。xxx
  • 广播IP:XXX.XXX.XXX.255 255.255.255.255(全网广播)
  • 组播IP:224.xxx.xxx.xxx ~ 239.xxx.xxx.xxx

端口号

  • 为了区分一台主机接收到的数据包应该转交给哪个任务来进行处理,使用端口号来进行区分。
  • TCP端口号和UDP端口号是独立的。
  • 端口号一般有LANA
  • 保留端口:1~1023(FTP:23 SSH:22 HTTP:80 HTTPS:469)

TCP编程

tcp编程API:


  • socket();//建立socket套接字
  • bind();//套接字绑定端口
  • listen();//监听端口
  • accept();//接收客户端链接
  • connect();//与服务端建立socket链接
  • read();//读取套接字内容,会阻塞
  • write();//向socket套接字中写内容。
  • close();//关闭socket链接。

TCP并发服务器:

  • TCP循环服务器:
socket();
bind();
listen();
while(1){
    accept();
    process();
    close();
}


  • TCP 多进程并发服务器:
socket();
bind();
listen();
while(1){
    accept();
    if(fork() == 0){
    process();
    close();
    exit();
    }
    close();
}


  • TCP多线程并发服务器:
socket();
bind(();
listen();
while(1){
    accept();
    if(pthread_create() != -1){
        process();
        close();
        exit();
    }
    close();
}


UDP网络编程

API

  • send()//类似write()
  • recv()//类似read()

服务端

  • socket()
  • bind()//绑定IP、端口
  • recvfrom()//阻塞等待接收消息
  • sendto()//发送消息
  • close()

客户端

  • socket()
  • sendto()//发送消息
  • sendto(int socket, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
  • dest_addr–发送目标的sock信息。
  • addrlen–发送目标的sock结构体长度。
  • recvfrom()//接收消息
  • recvfrom(int sockfd, void *buf, size_t, len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • src_addr–发送端的socket信息。
  • close()//关闭socket套接字

udp-server:


/*************************************************************************
  > File Name: udp_demo.c
  > Author: 
  > Mail: 
  > Created Time: 2019年05月25日 星期六 07时04分23秒
 ************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<strings.h>
#include<string.h>
#include<arpa/inet.h>
#define BUFSIZE 128
#define SERV_PORT 8888
#define QUIT_STR "quit"
int main(){
    //create socket
    int fd = -1;
    fd = socket(AF_INET,SOCK_DGRAM, 0);
    if(fd < 0){
        perror("socket fail\n");
        return -1;
    }
    int b_reuse = 1;
    //bind setopt
    //setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
    //bind
    struct sockaddr_in sin;
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SERV_PORT);
    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
    int ret = bind(fd, (struct sockaddr *)&sin, sizeof(sin));
    if(ret < 0){
        perror("bind fail\n");
        return -1;
    }
    char buf[BUFSIZE];
    struct sockaddr_in client_sin;
    socklen_t addrlen = sizeof(client_sin);
    char ipv4_addr[16];
    while(1){
        bzero(buf, BUFSIZE);
        bzero(ipv4_addr, sizeof(ipv4_addr));
        printf("recv msg waiting...\n");
        ret = recvfrom(fd, buf, sizeof(buf), 0,(struct sockaddr *)&client_sin, &addrlen);
        printf("recv msg success\n");
        if(ret < 0){
            perror("recvfrom fail\n");
            continue;
        }
        if(!inet_ntop(AF_INET, (void *)&client_sin.sin_addr, ipv4_addr, sizeof(client_sin))){
            perror("inet_ntop fail\n");
            return -1;
        }
        printf("Recived from(%s:%d), data: %s\n", ipv4_addr, ntohs(client_sin.sin_port), buf);
        if(!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))){//recv quit
            printf("Client(%s:%d) is exiting!\n", ipv4_addr, ntohs(client_sin.sin_port));
            break;
        }
    }
    printf("function over\n");
    return 0;
}


udp-client


/*************************************************************************
    > File Name: udp_demo.c
    > Author: 
    > Mail: 
    > Created Time: 2019年05月26日 星期日 07时03分53秒
 ************************************************************************/
#include<stdio.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<strings.h>
#include<string.h>
#include<stdlib.h>
#define BUFSIZE 128
#define QUIT_STR "quit"
void usage(char *s){
    printf("\n This is udp demo!\n");
    printf("\nUsage:\n\t %s serv_ip serv_port", s);
    printf("\n\t serv_ip: udp server ip address");
    printf("\n\t serv_port: udp server port \n\n");
}
int main(int argc, char **argv){
    int fd = -1;
    struct sockaddr_in sin;
    if(argc != 3){
        usage(argv[0]);
        printf("31\n");
        return -1;
    }
    int port = 0;
    port = atoi(argv[2]);
    if(port < 0 ||(port > 50000)){
        usage(argv[0]);
        printf("input port = [%d] 38\n", port);
        return -1;
    }
    if(fd = socket(AF_INET, SOCK_DGRAM, 0) < 0){
        perror("socket fail\n");
        return -1;
    }
    bzero(&sin, sizeof(sin));
    printf("-->port=[%d], addr=[%s]\n", port, argv[1]);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = inet_addr(argv[1]);
//    if(inet_pton(AF_INET, argv[1], (void *)&sin.sin_addr) != 1){
//        perror("inet_pton\n");
//        return -1;
//    }
    char buf[BUFSIZE];
    printf("UDP client starting ...OK\n");
    while(1){
        bzero(buf, BUFSIZE);
        printf("Please input the string to server:\n");
        if(fgets(buf, BUFSIZE -1, stdin) == NULL){
            perror("fgets fail\n");
            continue;
        }
        sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&sin, sizeof(sin));
        if(!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))){
            printf("Client is exited\n");
            break;
        }
    }
    printf("function over!\n");
    return 0;
}


网络编程 I/O多路复用

阻塞I/O模式

  • 阻塞 I/O模式是最普通使用的I/O模式,大部分程序使用的都是阻塞模式的I/O
  • 缺省情况下,套接字建立后所处于的模式就是阻塞I/O模式。
  • 前面学习的很多读写函数在调用过程中会发生阻塞。
  • 读操作中的read、recv、recvfrom
  • 写操作中的write、send
  • 其他操作:accept、connect

非阻塞I/O模式

  • 当我们将一个套接字设置为非阻塞模式,我们相当于高速系统内核,如果请求的I/O操作不能干马上完成就马上返回一个错误给我。
  • 当一个应用程序使用非阻塞模式的套接字,它需要使用一个循环来不停地测试是否一个文件描述符有数据可度,(成为polling)
  • 应用程序不停的polling内核来检查是否I/O操作已经就绪,这将是一个极浪费CPU资源的操作。
  • 这种模式使用中不普遍。
  • 使用fcntl()函数来设置一个套接字描述符为非阻塞模式

多路复用

Linux中每个进程默认情况下,最多可以打开1024个文件,最多有1024个文件描述符

文件描述符的特点:


  • 非负整数
  • 从最小可用的数字来分配
  • 每个进程启动时默认打开0、1、2三个文件描述符。
  • 多路复用API
  • select()
int main(){
    fd_set rset;
    fd = socket();
    bind();
    listen();
    maxfd = fd;
    FD_ZERO(&rset);
    FD_SET(fd, &rset);//将建立好的套接字加入集合中。
    struct timeval tout;
    tout.tv_sec = 5;
    tout.tv_usec = 0;
    select(maxfd +1 , &rset, NULL, NULL, &tout);
    if(FD_ISSET(fd, &rset)){
        newfd = accept(fd, ...);    
    }
    //依次判断已建立的客户端是否有数据。
}
相关文章
|
4月前
|
安全 Linux 网络安全
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
139 0
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
|
5月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
321 18
|
5月前
|
网络协议 关系型数据库 Linux
【App Service Linux】在Linux App Service中安装 tcpdump 并抓取网络包
在App Service for Linux环境中,无法像Windows一样直接使用网络排查工具抓包。本文介绍了如何通过TCPDUMP在Linux环境下抓取网络包,包括SSH进入容器、安装tcpdump、执行抓包命令及下载分析文件的完整操作步骤。
259 5
|
6月前
|
Web App开发 网络协议 Linux
【Linux】网络基础
TCP/IP五层模型是网络通信的基础框架,将复杂的数据传输过程分为物理层、数据链路层、网络层、传输层和应用层,每层各司其职,协同完成远程通信。该模型确保了不同设备和网络之间的互联互通,是现代互联网运行的核心机制。
438 5
|
6月前
|
网络协议 Linux 开发者
深入Linux中UDP网络通信机制编程探索
以上步骤概述了Linux中UDP网络通信的编程机制。在实现时,因关注细节和上下文环境可能有所调整,但大致流程是一致的。这些知识片段旨在帮助开发者快速上手Linux下的UDP编程,并提供可靠的信息作为编程的基础。在编程实践中,应结合实际业务需求,设计合适的数据传输协议,确保数据的正确性和实时性。
168 0
|
8月前
|
安全 网络协议 Linux
Linux网络应用层协议展示:HTTP与HTTPS
此外,必须注意,从HTTP迁移到HTTPS是一项重要且必要的任务,因为这不仅关乎用户信息的安全,也有利于你的网站评级和粉丝的信心。在网络世界中,信息的安全就是一切,选择HTTPS,让您的网站更加安全,使您的用户满意,也使您感到满意。
236 18
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
493 2
|
8月前
|
Linux 数据安全/隐私保护
使用Linux命令行接入无线网络Wi-Fi的示例。
现在,你已经使用命令行成功地连接到 Wi-Fi 网络了。这两个示例涵盖了用 `nmcli` 和 `wpa_supplicant` 连接无线网络的常见场景,让你能够不依赖图形化界面来完成这个任务。在日常使用中熟练掌握这些基本操作能增强你对 Linux 系统的理解,帮助你更有效地处理各种问题。
568 12
|
8月前
|
安全 Ubuntu Linux
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
292 0
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
|
10月前
|
Ubuntu Linux
Linux系统管理:服务器时间与网络时间同步技巧。
以上就是在Linux服务器上设置时间同步的方式。然而,要正确运用这些知识,需要理解其背后的工作原理:服务器根据网络中的其他机器的时间进行校对,逐步地精确自己的系统时间,就像一只犹豫不决的啮齿动物,通过观察其他啮齿动物的行为,逐渐确定自己的行为逻辑,既简单,又有趣。最后希望这个过程既能给你带来乐趣,也能提高你作为系统管理员的专业素养。
1470 20