linux应用之--网络编程

linux网络编程

    一:网络参考模型参考模型,如下图所示:

    linux应用之--网络编程_第1张图片

    二:TCP/IP协议

TCP协议(传输控制协议)和UDP协议(用户数据包协议)是工作在传输层的。  其中TCP协议是面向连接的,UDP是面向无连接的。以太网协议是工作在网络接口层的,应用程序(像tftp,dns等)是工作在应用层的。IP协议工作在网络层。一个以太网包里面含有一个IP包,一个IP包里面含有一个TCP包或者UDP包。

三:socket网络编程。

Linux下面的网络编程始终是围绕socket展开的。对于socket的理解,我只能说是达到了表面,也查过很多资料。说是socket类似linux下的文件操作。使用socket函数可以产生一个socket的描述符,是一个整形量,后续的操作都是围绕这个整形描述符进行的。另外要明白一点,网络通信无非就是网络间的两个进程之间的通信。那么他们是靠什么进行相互识别的呢。主要靠两个参数一个是IP,一个是端口号。记住这两个特性。

产生socket描述符,调用函数int socket(a , b , c);这个函数有三个参数,第一个参数表征的是协议类型,一般用AF_INET,表示的是IP4,如果以后IP6盛行了,那么就改用AF_INET6就可以了。第二个参数是表示创建的socket类型,socket类型主要有三种,一是流式套接字,用宏SOCK_STREAM表示,第二种是数据报套接字,用宏SOCK_DGRAM表示,第三种是原始套接字。另外注意,SOCK_STREAM针对的TCP面向连接的通信,SOCK_DGRAM是针对UDP面向无连接的通信。至于都三个参数,其实也是相关协议,一般填0即可。

第二步是配置描述符了。上面已经提到过,用来描述网络间进程的主要有两个参数,一是IP地址,另一个就是端口号了,那么对于一个刚刚创建的套接字描述符,也是使用IP号和端口号来描述的,而这些描述套接字的东西都用一个sruct sockaddr 或者说其替代结构 struct sockaddr_in 来描述的。因为真正描述一个套接字属性的是结构sruct sockaddr_in,所以还得把产生的套接字跟这个结构相互绑定。当然,在绑定之前要对struct sockaddr_in 这个结构进行填充。因为这个结构完全是为了代替struct sockaddr 而来的,为了使其大小一致,剩余字节数的空间需要填充为0.也就是说,先要bzero(&addr,sizeof(struct sockaddr));然后设置IP号。如果是服务器,那么IP指的是将要与其通信的客户端IP,如果允许所有IP的客户端访问,那么就填充INADDR_ANY。否者就填充实际的IP号。如果对于客户端,那么填的就是其实际要访问的服务器的IP地址了。然而,填充IP地址也不是一件想当然的事情。因为我们平常见到的IP,都是字符串型的,而在struct sockaddr_in 这个结构里面,是用一个struct in_addr 来保存IP地址的。这个结构里面就只有一个成员,那就是一个32位的整形。所以字符型的IP地址和32位的整形IP地址之间就需要转换了。有两个函数是直接针对这个转换过程的。一个是inet_aton(字符串IP,struct in_addr * addr);这个函数是把字符串ip转换成32位整形的函数。成功返回0.另一个与之相对的函数就是:

char *inet_ntoa(struct  in_addr );除了这两种直接转换之外,还有一种方法。就是利用hostent结构。hostent结构里面有一个成员,叫做h_addr里面保存的就是32位整形的IP地址。那如何为hostent填充IP地址(使用字符串型的IP)呢?这就需要用另外一个函数

struct  hostent *  gethostbyname(char *x) 其中的cahr*x表示的是字符型的IP地址或者是字符型的网址。然后再调用struct hostent 中的h_addr 即可获得32位整形ip。介绍完这里,那么对于struct sockaddr_in 这个结构已经可以顺利填充完了。下面的操作就要分类来进行了。如果是服务器(不论是TCP的还是UDP的)那么调用bind函数即可绑定。

Int  bind(a , b, c)a是所要绑定的套接字,是由socket函数返回的值,b是一个指针,其指向struct sockaddr结构。一般把前面提到的已经填充好的struct sockaddr_in 结构用强制转换成(struct sockaddr *)即可。第三个参数是一个整形量,用来描述struct sockaddr的大小。一般直接用sizeof(struct sockaddr)或者sizeof(struct sockaddr_in).这样就完成了服务器端的socket描述符与ip地址与端口信息的绑定。如果是客户端,那么要分情况了。若是基于TCP的客户端,那么就调用connect函数,将socket描述符与struct sockaddr_in进行绑定。该函数是这样的。Int connect(a,b,c);其参数完全与前面提到的bind函数一致。所以这里就不再赘述。如果是基于UDP的客户端,那么直接调用sendto函数即可,这个函数即完成了绑定的作用,又完成了发送数据的作用。其原型为:

Sendto(sockfd,buffer,lenth,0,(struct sockaddr*)addr ,sizeof(structsockaddr)).第一个参数为客户端建立的socket描述符,第二个参数为发送缓冲区,第三个参数为发送的字节数,后面两个参数就不介绍了。

第三步就可以开始通信了。当然,其实在第二步中,对于UDP类型的客户端,其在配置SOCKET描述符的时候已经在通信了。然后服务器端再调用ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen); 注意最后一个参数是指针即可。若是TCP类型的通信。那么服务器端先调用listen函数设置好最大连接数,然后调用accept函数即可,当建立好连接之后,可以使用read,write函数进行通信。而对于客户端,需用先调用connect函数,建立好连接之后既可以用read,write函数,进行通信了。

第四步,关闭套接字描述符。对于UDP类型的,服务器和客户端各有一个描述符需要关闭,而对于TCP类型的,服务器有两个套接字需要关闭,客户端有一个套接字需要关闭。关闭使用函数close即可。

你可能感兴趣的:(linux应用之--网络编程)