最新Linux网络编程笔记(修订版).doc
《最新Linux网络编程笔记(修订版).doc》由会员分享,可在线阅读,更多相关《最新Linux网络编程笔记(修订版).doc(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、精品资料Linux网络编程笔记(修订版).|我的网络编程笔记, 因为最近又要做Linux下的网络编程,故重新修订, 其中一些内容参考了文末的链接及文章1. 基本概念说到网络编程,不得不先提到OSI参考模型,其七层模型从下到上分别为1.物理层(Physical Layer,PH)2.数据链路层(Data Link Layer,DL)3.网络层(Network Layer,N)4.运输层(Transport Layer,T)5.会话层(Session Layer,S)6.表示层(Presentation Layer,P)7.应用层(Application Layer,A)现在最流行的网络协议无疑就
2、是TCP/IP(Transmission Control Protocol/Internet Protocol)协议.注:l IP (Internet Protocol),网际协议;IP是TCP/IP的最底层,高层协议都要转化为IP包,IP包含了源地址和目的地址,路由决策也发生在IP层; l ICMP (Internet Control Message Protocol),网际报文协议;它包括了数据包的错误、控制等相关信息。比如ping命令就是利用ICMP来测试一个网络的连接情况的工具; l TCP (Transmission Control Protocol),传输控制协议。TCP运行在IP
3、之上,是基于数据流连接和面向的协议,应用程序把数据要经过TCP/IP的分割成若干包,这样数据就以字节流发送和接收,到达目的地后,TCP/IP再按顺序进行组装。TCP/IP要保证机器与机器之间的连接的可靠性,还要有纠错。TCP是否被选择,取决于应用程序或服务; l UDP (User Datagram Protocol) ,用户数据报协议 ,象TCP一样运行在IP之上,是基于数据报或分组的协议,UDP/IP可以直接发送和接收数据报文,而不必做验证,这一点与TCP/IP不同。TCP是否被选择,取决于应用程序或服务; 2. 基本接口以Unix/Linux平台为例,系统会建立许多网络服务程序 $net
4、stat -aProto Recv-Q Send-Q Local Address Foreign Address Statetcp 0 0 *:1975 : LISTENudp 0 0 *:1978 :tcp 0 0 MYServer:34320 192.168.1.2:1521 ESTABLISHED以上可以看到有三个网络连接,一个是TCP接连在1975端口侦听,一个UDP连接在1978端口,另外一个TCP连接是连接到DB的我们可以看出,客户端程序需要通过”主机名:端口号”与服务器建立连接.主机名其实就是IP地址. 上面的MYServer其实是192.168.1.3, 这样的主机名与IP的对
5、应关系由本机的host文件或DNS服务器解析提供. $more /etc/hosts# that require network functionality will fail.127.0.0.1 localhost.localdomain localhost192.168.1.3 MYServer$ more /etc/resolv.confnameserver 192.168.1.1当然,我们在编程时无需查询这些文件或服务器,系统提供了API:gethostbyname/gethostbyaddr #include extern int h_errno;struct hostent *ge
6、thostbyname(const char *name);#include /* for AF_INET */struct hostent *gethostbyaddr(const char *addr, int len, int type);它们会返回一个指针,指向如下结构的对象 struct hostent char h_name; / official name */ char *h_aliases; /* alias list */ int h_addrtype; /* address type */ int h_length; /* address length */ char *
7、h_addr_list; /* address list */;#define h_addr h_addr_list0/* backward compatibility */h_addr_list是一个与域名对应的IP地址的列表,勤快的程序员会依次尝试连接列表中返回的IP地址懒惰的程序员只会用h_addr,h_addr_list列表中的第一个IP地址不同的应用程序使用不同的端口和协议,比如常用的ftp就用21端口和tcp协议$more /etc/services# service-name port/protocol aliases . # comment fsp fspdssh 22/tcp
8、 # SSH Remote Login Protocolssh 22/udp # SSH Remote Login Protocoltelnet 23/tcptelnet 23/udp# 24 - private mail systemsmtp 25/tcp mailsmtp 25/udp mail.同样,程序中是无需查询这个文件的,Unix提供了getservbyname#include struct servent *getservbyname(const char *name, const char *proto);返回struct servent char s_name; / offi
9、cial service name */ char *s_aliases; /* alias list */ int s_port; /* port number */ char s_proto; / protocol to use */ 知道主机名(IP)和端口号,我们就可以编写在这台主机的运行的或是连接到它的网络应用程序了Unix/Linux系统中是通过提供套接字(socket)来进行网络编程的.网络程序通过socket和其它几个函数的调用,会返回一个通讯的文件描述符,我们可以将这个描述符看成普通的文件的描述符来操作,可以通过向描述符读写操作实现网络之间的数据交流.2.1. 打开一个soc
10、ket int socket(int domain,int type,int protocol)domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等).AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程主机之间通信(当我们mansocket时发现domain可选项是PF_*而不是AF_*,因为glibc是posix的实现所以用PF代替了AF,不过我们都可以使用的).type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等)SOCK_STREAM表明我们用的是TCP协
11、议,这样会提供按顺序的,可靠,双向,面向连接的比特流.SOCK_DGRAM表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了socket为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况.2.2. 将socket绑定定指定的端口bindint bind(int sockfd,struct sockaddr* my_addr,int addrlen)sockfd:是由socket调用返回的文件描述符.addrlen:是sockaddr结构的长度.my_
12、addr:是一个指向sockaddr的指针.在中有sockaddr的定义structsockaddrunisgnedshortas_family;charsa_data14;不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(structsockaddr_in)来代替.在中有sockaddr_in的定义structsockaddr_inunsignedshortsin_family;unsignedshortintsin_port;structin_addrsin_addr;unsignedcharsin_zero8;我们主要使用Internet所以sin_family一般为AF
13、_INET,sin_addr设置为INADDR_ANY表示可以和任何的主机通信,sin_port是我们要监听的端口号.sin_zero8是用来填充的.bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样2.3. 侦听socketlisten (服务器端)int listen(int sockfd,int backlog)sockfd:是bind后的文件描述符.backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时,使用这个表示可以介绍的排队长度.listen函数将bind的文件描述符变为监听套接字.返回的情况和bind一样.
14、2.4. 等待接收请求accept (服务器端)int accept(int sockfd, struct sockaddr*addr,int* addrlen)sockfd:是listen后的文件描述符.addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了.bind,listen和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个客户程序发出了连接.accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了.失败时返回-12.5. 连接到socketconnectint connect(int soc
15、kfd,struct sockaddr* serv_addr,int addrlen)sockfd:socket返回的文件描述符.serv_addr:储存了服务器端的连接信息.其中sin_add是服务端的地址addrlen:serv_addr的长度connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符失败时返回-1.2.6. 利用socket传输数据2.6.1. read和writessize_t read(int fd,void *buf,size_t nbyte) read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果
16、返回的值是0表示已经读到文件的结束了,小于0表示出现了错误.如果错误为EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题. 和上面一样,我们也写一个自己的读函数.ssize_t write(int fd,const void *buf,size_t nbytes) write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能. 1)write的返回值大于0,表示写了部分或者是全部的数据. 2)返回的值小于0,此时出现了错误.我们要根据错误类型来处
17、理. 如果错误为EINTR表示在写的时候出现了中断错误. 如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接). 为了处理以上的情况,我们自己编写一个写函数来处理这几种情况.2.6.2. recv和send和read和write差不多.不过它们提供 了第四个参数来控制读写操作. int recv(int sockfd,void *buf,int len,int flags) int send(int sockfd,void *buf,int len,int flags) 前面的三个参数和read,write一样,第四个参数可以是0或者是以下的组合 _ | MSG_DONTROUTE |
18、 不查找路由表 | | MSG_OOB | 接受或者发送带外数据 | | MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 | | MSG_WAITALL | 等待所有数据 | |-| MSG_DONTROUTE:是send函数使用的标志.这个标志告诉IP协议.目的主机在本地网络上面,没有必要查找路由表.这个标志一般用网络诊断和路由程序里面. MSG_OOB:表示可以接收和发送带外的数据.关于带外数据我们以后会解释的. MSG_PEEK:是recv函数的使用标志,表示只是从系统缓冲区中读取内容,而不清楚系统缓冲区的内容.这样下次读的时候,仍然是一样的内容.一般在有多个进程读写数据时可以
19、使用这个标志. MSG_WAITALL是recv函数的使用标志,表示等到所有的信息到达时才返回.使用这个标志的时候recv回一直阻塞,直到指定的条件满足,或者是发生了错误. 1)当读到了指定的字节时,函数正常返回.返回值等于len 2)当读到了文件的结尾时,函数正常返回.返回值小于len 3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno) 如果flags为0,则和read,write一样的操作.还有其它的几个选项,不过我们实际上用的很少,可以查看Linux Programmers Manual得到详细解释. 2.6.3. recvfrom和sendto int recvfr
20、om(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from int *fromlen) int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to int tolen) sockfd,buf,len的意义和read,write一样,分别表示套接字描述符,发送或接收的缓冲区及大小.recvfrom负责从sockfd接收数据,如果from不是NULL,那么在from里面存储了信息来源的情况,如果对信息的
21、来源不感兴趣,可以将from和fromlen设置为NULL.sendto负责向to发送信息.此时在to里面存储了收信息方的详细资料. 2.6.4. recvmsg和sendmsg recvmsg和sendmsg可以实现前面所有的读写函数的功能. int recvmsg(int sockfd,struct msghdr *msg,int flags) int sendmsg(int sockfd,struct msghdr *msg,int flags) struct msghdr void *msg_name; int msg_namelen; struct iovec *msg_iov; i
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最新 Linux 网络 编程 笔记 修订版
限制150内