• 嵌入式Linux网络编程


    参考书籍:《从实践中学嵌入式linux应用程序开发》(华清远见嵌入式学院)

    代码下载:http://download.csdn.net/detail/klcf0220/5354885

    资料下载:http://www.kuaipan.cn/file/id_43409466388906157.htmhttp://download.csdn.net/detail/klcf0220/7058371)  、  http://www.kuaipan.cn/file/id_43409466388906143.htm

    参考链接:http://www.cnblogs.com/Robotke1/archive/2013/05/07/3064575.html

    TCP/IP协议

    参考链接: http://www.cnblogs.com/dann/archive/2013/02/14/2909869.html

    OSI层次模型:

    OSI层次模型中各层的功能:
       (1) 物理层(PH),确定物理设备接口,提供点-点的比特流传输的物理链路;
       (2) 数据链路层(DL),利用差错处理技术,提供高可靠传输的数据链路;
       (3) 网络层(N),利用路由技术,实现用户数据的端-端传输;
       (4) 运输层(T),屏蔽子网差异,用户要求和网络服务之间的差异;
       (5) 会话层(S),提供控制会话和数据传输的手段 ;
       (6) 表示层(P),解决异种系统之间的信息表示问题,屏蔽不同系统在数据表示方面的差异;
       (7) 应用层(A),利用下层的服务,满足具体的应用要求。

    TCP/IP协议各层的解析:

    (1)网络接口层

      TCP/IP协议模型的基层,负责数据帧的发送和接收。对应OSI模型中的物理层和数据链路层,是TCP/IP的最底层,不过通常在描述TCP/IP模型时还是会划分具体为物理层(PHY)和数据链路层(MAC)。主要负责将二进制流转换为数据帧,并进行数据帧的发送和接收。数据帧是网络传输的基本单元。

    (2)网络层

      通过互联协议将数据包封装成互联网数据包,并运行必要的路由算法。这里有4种互联协议。

      (a)网际协议IP:负责在主机和网络之间的路径寻址和数据包路由。

      (b)地址解析协议ARP:获得同一物理网络中的主机硬件地址。

      (c)网际控制消息协议ICMP:发送消息,并报告有关数据包的传送错误。

      (d)互联组管理协议IGMP:用来实现本地多路广播路由器报告。

    (3)传输层

      传输协议负责提供应用层程序之间的通信服务。传输协议的选择根据数据传输方式而定。主要有以下2种传输协议:

      (a)传输控制协议TCP:为应用程序提供可靠的通信连接,适用于要求得到响应的应用程序。

      (b)用户数据包协议UDP:提供无连接通信,且不对传输包进行可靠性确认。

    (4)应用层

      应用程序通过这一层访问网络,主要包括常见的FTP、HTTP、DNS和TELNET协议。

    套接字

    Socket有三种类型:
    1)流式套接字(SOCK_STREAM)   基于TCP协议
    2)数据报套接字(SOCK_DGRAM)    基于UDP协议
    3)原始套接字(SOCK_RAW)       基于底层协议如IP或ICMP协议,主要用于新的网络协议的开发。

    在socket程序设计中,struct sockaddr 和struct  sockaddr_in用于记录网络地址,

    struct scokaddr
    {
        unsigned short sa_family;//地址族
        char sa_data[14];//14字节的协议地址,包含该socket的IP地址和端口号
    };
    struct scokaddr_in
    {
        short int sin_family;//地址族
        unsigned short int sin_port;//端口号
        struct in_addr sin_addr;//IP地址
        unsigned char sin_zero[8];//填充0以保持与struct sockaddr同样大小
    };

    这两个数据类型是等效的,可以相互转化,通常sockaddr_in 数据类型使用更为方便。

    sa_family 字段可选的常见值:(需要#include<netinet/in.h>头文件)
    AF_INET:IPv4协议
    AF_INET6:IPv6协议
    AF_LOCAL:UNIX域协议
    AF_LINK:链路地址协议
    AF_KEY:秘钥套接字

    数据存储优先顺序:
    字节序的转因为计算机存储有两种字节优先排序:高位字节优先(即大端模式)和低位地址优先(即小端模式),Internet上数据以高位字节优先顺序在网络上传输。所以有些情况下,需要对这两字节存储优先顺序进行相互转化。这里用到4个函数:htons() ,htonl() ,ntohs() ,ntohl();  
    其中h代表host,n代表network,s代表short,l代表long。通常16位的IP端口号用 s 代表,而IP地址用 l 来表示。

    地址格式转换:
    用户表达地址时通常采用点分十进制表示的数值字符串,而在通常使用的socket编程中所用的则是二进制值,这就需要将两个数值进行转换。
    在IPv4中用到的函数有inet_aton(),inet_addr(),inet_ntoa();
    而IPv4和IPv6兼容的函数有inet_pton()和inet_ntop()。

    套接字编程

    socket()                  //创建一个socket
    bind()                      //该函数用于将sockaddr结构的地址信息与套接字进行绑定。主要用于TCP的连接,而在UDP的连接中则没有必要。
    connect()               //该函数用于服务器建立连接
    listen()                    //创建一个等待队列,在其中存放未处理的客户端连接请求。
    accept()                 //用于等待并接收来自客户端的socket连接请求
    send() ,sendto      //发送数据
    recv() ,recvfrom   //接收数据

    Socket网络编程流程图http://blog.csdn.net/zhangyaowen123123/article/details/6738562

    编程实例:

    /*server.c*/
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<errno.h>
    #include<string.h>
    #include<unistd.h>
    #include<netinet/in.h>
    #define PORT 4321
    #define BUFFER_SIZE 1024
    #define MAX_QUE_CONN_NM 5
    int main()
    {
        struct sockaddr_in server_sockaddr,client_sockaddr;
        int sin_size,recvbytes;
        int sockfd,client_fd;
        char buf[BUFFER_SIZE];
        
        //建立socket链接
        if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
        {
            perror("socket");
            exit(1);
        }
        printf("socket is = %d\n",sockfd);
    
        //设置sockaddr_in结构体中相关参数
        server_sockaddr.sin_family = AF_INET;
        server_sockaddr.sin_port = htons(PORT);
        server_sockaddr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(server_sockaddr.sin_zero),8);
        
        int i =1;//允许重复使用本地地址与套接字进行绑定
        setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
        
        //绑定套接字
        if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1)
        {
            perror("bind");
            exit(1);
        }
        printf("bind success\n");
    
        //listen()
        if(listen(sockfd,MAX_QUE_CONN_NM) == -1)
        {
            perror("listen");
            exit(1);
        }
        printf("listen ......\n");
    
        //accept()
        sin_size = sizeof(client_sockaddr);
        if((client_fd = accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size)) == -1)
        {
            perror("accept");
            exit(1);
        }
        
        //recv()
        memset(buf,0,sizeof(buf));
        if((recvbytes = recv(client_fd,buf,BUFFER_SIZE,0)) == -1)
        {
            perror("recv");
            exit(1);
        }
        printf("received a message:%s\n",buf);
        close(sockfd);
        exit(0);
    }
    
    /*client.c*/
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<errno.h>
    #include<string.h>
    #include<unistd.h>
    #include<netinet/in.h>
    #include<netdb.h>//一定要加上这个头文件,不然会报“提领指向不完全类型的指针”的错误
    #define PORT 4321
    #define BUFFER_SIZE 1024
    int main(int argc,char *argv[])
    {
        struct sockaddr_in serv_addr;
        int sendbytes,sockfd;
        struct hostent *host;
        char buf[BUFFER_SIZE];
        
        if(argc < 3)
        {
            fprintf(stderr,"USAGE: ./client Hostname(or ip address) Text\n");
            exit(1);
        }
        
        //地址解析函数
        if((host = gethostbyname(argv[1])) == NULL)
        {
            perror("gethostbyname");
            exit(1);
        }
        
        memset(buf,0,sizeof(buf));
        sprintf(buf,"%s",argv[2]);
        //建立socket
        if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
        {
            perror("socket");
            exit(1);
        }
    
        //设置sockaddr_in结构体中相关参数
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);
        serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
        bzero(&(serv_addr.sin_zero),8);
        
        //connect()
        if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) == -1)
        {
            perror("connect\n");
            exit(1);
        }
        
        //send()
        if((sendbytes = send(sockfd,buf,strlen(buf),0)) == -1)
        {
            perror("send");
            exit(1);
        }
        close(sockfd);
        exit(0);
    }
    作者:快乐出发0220 ;Android群:151319601 ; Linux群:96394158 ;转载请注明出处 http://klcf0220.cnblogs.com/ !!!
  • 相关阅读:
    POJ 3685 Matrix (二分套二分)
    mybatis-plus
    mysql 5.7 压缩包安装教程
    mysql备份
    mysql外键策略
    springboot使用RestTemplate以post方式发送json字符串参数(以向钉钉机器人发送消息为例)
    查询优化
    Spring Boot 创建定时任务(配合数据库动态执行)
    解决springboot序列化 json数据到前端中文乱码问题
    Mybatis 批量插入
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3066977.html
Copyright © 2020-2023  润新知