参考书籍:《从实践中学嵌入式linux应用程序开发》(华清远见嵌入式学院)
代码下载:
http://download.csdn.net/detail/klcf0220/5354885
资料下载:
http://www.kuaipan.cn/file/id_43409466388906157.htm(
http://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
头文件)
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
#include
#include
#include
#include
#include<string.h>
#include
#includein.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
",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
");
//listen()
if(listen(sockfd,MAX_QUE_CONN_NM) == -1)
{
perror("listen");
exit(1);
}
printf("listen ......
");
//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
",buf);
close(sockfd);
exit(0);
}
/*client.c*/
#include
#include
#include
#include
#include
#include<string.h>
#include
#includein.h>
#include//一定要加上这个头文件,不然会报“提领指向不完全类型的指针”的错误
#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
");
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
");
exit(1);
}
//send()
if((sendbytes = send(sockfd,buf,strlen(buf),0)) == -1)
{
perror("send");
exit(1);
}
close(sockfd);
exit(0);
}