嵌入式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);
}
posted @ 2013-05-11 22:09  不止所见  阅读(1109)  评论(0编辑  收藏  举报