Linux环境下网络编程杂谈<<转>>

  今天我们说说“Pre-网络编程”。内容比较杂,但都是在做网络应用程序开发过程中经常要遇到的问题。

  一、大端、小端和网络字节序

  小端字节序:little-endian,将低字节存放在内存的起始地址;

  大端字节序:big-endian,将高字节存放在内存的其实地址。

例如,数字index=0x11223344,在大小端字节序方式下其存储形式为:

  上图一目了然的可以看出大小端字节序的区别。

  还有另外一个概念就是网络字节序。网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian方式。注意:X86系列CPU都是小端little-endian字节序,即低字节存低位,高字节存高位。

  为此,Linux专门提供了字节转换函数.

unsigned long  int htonl(unsigned long  int hostlong)

unsigned short int htons(unisgned short int hostshort)

unsigned long  int ntohl(unsigned long  int netlong)

unsigned short int ntohs(unsigned short int netshort)

看个例子:

  在这四个转换函数中,h代表host,n代表 network,s代表short,l代表long 。htonl()函数的意义是将本机器上的long数据转化为网络上的long。其他几个函数的意义也差不多。

也就是说对于从网络上接收到的非单子节的基本数据类型数据,首先需要用ntohl(s)将其转换成本地字节序;同理,发往网络的非单子节的基本数据类型数据,首先用htonl(s)将其转换成网络字节序。这里最常见的就是IP地址和端口号。

  二、点分十进制格式的IP地址和32bit的IP地址

我们常见的IP地址都是以点分十进制格式表示,例如“172.18.1.231”。而在程序中基本是以如下的结构表示一个IP:

struct in_addr {
         __be32     s_addr; //其实就是一个32bit的数字

};

它和点分十进制格式的IP地址可以通过一组API实现相互转换:

int inet_aton(const char *cp,struct in_addr *inp) 无效的地址cp则返回0;否则返回非0

char *inet_ntoa(struct in_addr in) 将一个32位的IP地址转换成点分十进制字符串。

这两个函数所要求的struct in_addr{}参数均为网络字节序。

继续看例子:

“192.168.11.23”转换成数字就是0xc0a80b17,是网络字节序的。如果直接打印,那么本地按照小端字节序来输出,结果为net addr = 170ba8c0,刚好和实际相反。当我们先将其转换成本地字节序,然后再输出时结果就OK了,即host addr = c0a80b17。同理,inet_ntoa()也类似。

  三、网络主机名和IP地址的对应关系

在做网络编程时经常要碰到的一个问题就是根据对方主机名来获取其IP地址,或者根据IP地址反过来解析主机名和其他信息。Linux提供了两个常用的API:

struct hostent *gethostbyname(const char *name);

struct hostent *gethostbyaddr(const void *addr, int len, int type);

这两个函数失败时返回NULL且设置h_errno错误变量,调用hstrerror(h_errno)或者herror("Error");可以得到详细的出错信息。成功时均返回如下结构:

struct hostent {

     char    *h_name;        /* 主机名*/

     char    **h_aliases;    /* 主机别名的列表*/

     int     h_addrtype;     /* 地址类型,AF_INET或其他*/

     int     h_length;       /* 所占的字节数,IPv4地址都是4字节 */

     char    **h_addr_list;  /* IP地址列表,网络字节序*/

}

#define h_addr  h_addr_list[0]  /*后向兼容 */

gethostbyname可以将机器名(如www.google.com)转换为一个结构指针,gethostbyaddr可以将一个32位的IP地址(C0A80001)转换为结构指针。对于gethostbyaddr函数来说,输入参数“addr”的类型根据参数“type”来确定,目前type仅取AF_INET或AF_INET6。例如,type=2(即AF_INET),则addr就必须为struct in_addr{}类型。

继续看例子:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>

int main(int arg,char** argv){

  struct hostent *host,*host2;

  if(NULL == (host = gethostbyname(argv[1]))){

          herror("Error");

          return 1;

  }

  printf("name = %s\n",host->h_name);

  printf("aliases = %s\n",*host->h_aliases);

  printf("add type = %d\n",host->h_addrtype);

  printf("len = %d\n",host->h_length);

  printf("IP=%s\n",inet_ntoa(*(struct in_addr*)host->h_addr));

  printf("=================================\n");

  struct in_addr maddr;

  if(0 == inet_aton(argv[2],&maddr)){

          return 0;

  }

  char* c = (char*)&maddr;

  printf("org = %x.%x.%x.%x\n",*(c)&0xff,*(c+1)&0xff,*(c+2)&0xff,*(c+3)&0xff);

  if(NULL == (host2 = gethostbyaddr(&maddr,4,2))){

          printf("Error:%s\n",hstrerror(h_errno));

          return 1;

  }

  printf("name = %s\n",host2->h_name);

  printf("aliases = %s\n",*host2->h_aliases);

  printf("add type = %d\n",host2->h_addrtype);

  printf("len = %d\n",host2->h_length);

  printf("IP=%s\n",inet_ntoa(*(struct in_addr*)host2->h_addr));

  return 0;

}

运行结果如下:

当我们调用gethostbyaddr根据主页的IP地址获取其站点信息时返回的错误是“未知的主机”错误,原因留给大家自己思考吧。这充分说明对了于gethostbyname()函数和gethostbyaddr()函数的调用一定要判断其返回值。

  转载自:http://blog.chinaunix.net/uid-23069658-id-3271110.html

时间: 2024-10-12 08:22:00

Linux环境下网络编程杂谈<<转>>的相关文章

Linux 环境下 网络IO模型

本文讨论的背景是Linux环境下的network IO. IO发生时涉及的对象和步骤: 对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel).当一个read操作发生时,它会等待内核经历两个阶段: 1  内核数据准备 (Waiting for the data to be ready) 2  内核把数据从内核空间,拷贝到用户空间中 (Copying the data from

【Linux&amp;C++】Linux环境下C++编程

在阅读的过程中有任何问题,欢迎一起交流 邮箱:[email protected]   QQ:1494713801 在linux下,开发工具被切割成一个个独立的小工具.各自处理不同的问题.例如: 编辑器(emacs, vim)用来进行编辑程序的 调试器(gdb) 用来调试程序 编译器(GCC) 用来编译和链接程序的 性能分析工具(gcov, gprof) 用来优化程序的 文档生成器(doxygen) 用来生成文档的 同时,还有一些系统工具和系统知识,我们是很有必要了解的: makefile  程序

【原创】Linux环境的图形系统和AMD显卡驱动编程(1)——Linux环境下的图形系统简介

Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区开发开发了一些新的图形系统,比如Wayland图形系统. 由于图形系统.3D图形本身的复杂以及历史原因,Linux下的图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码分析或者驱动编程的书籍都很少介绍显卡驱动).在后续一系列文章中,笔者将从对AMD硬件编程的角度出发对部分问题做一个简单的

Golang在Linux环境下的POSIX风格socket编程

这里给出一个服务端和客户端,服务端可以接受多个连接,并且利用Go的杀手特性go和channel来替代select进行数据的接收. 服务端: package main import ( "fmt" . "syscall" ) func RecvRoutine(sockfd int, session chan string) { var buffer []byte = make([]byte, 3000) for { if length, err := Read(soc

Linux环境下查看网络性能的基本命令

                 Linux环境下查看网络性能的基本命令 由于Linux经常使用的是字符界面,而且Linux的功能比较强大,具有默认路由功能,相当于网关和路由器.在网络性能方面也比较稳定,而且配置简单.当然在配置网络的时候可能会发生网络的连通性不稳定或者不通.一下命令或许对大家有所帮助: 1.curl & wget 使用curl或wget命令,不用离开终端就可以下载文件.如你用curl,键入curl -O后面跟一个文件路径.wget则不需要任何选项.下载的文件在当前目录. cur

Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介

转:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区开发开发了一些新的图形系统,比如Wayland图形系统. 由于图形系统.3D图形本身的复杂以及历史原因,Linux下的图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind

Linux环境下的高级隐藏技术

linux相关资料由兄弟连官方分享 摘要:本文深入分析了Linux环境下文件.进程及模块的高级隐藏技术,其中包括:Linux可卸载模块编程技术.修改内存映象直接对系统调用进行修改技术,通过虚拟文件系统proc隐藏特定进程的技术. 隐藏技术在计算机系统安全中应用十分广泛,尤其是在网络攻击中,当攻击者成功侵入一个系统后,有效隐藏攻击者的文件.进程及其加载的模块变得尤为重要.本文将讨论Linux系统中文件.进程及模块的高级隐藏技术,这些技术有的已经被广泛应用到各种后门或安全检测程序之中,而有一些则刚刚

mosquitto在Linux环境下的部署/安装/使用/测试

mosquitto在Linux环境下的部署 看了有三四天的的源码,(当然没怎么好好看了),突然发现对mosquitto的源码有了一点点感觉,于是在第五天决定在Linux环境下部署mosquitto. 使用传统源码安装步骤: 步骤1:http://mosquitto.org/files/source/官网下载源码,放到Linux环境中.解压后,找到主要配置文件config.mk,其中包含mosquitto的安装选项,需要注意的是,默认情况下mosquitto的安装需要OpenSSL(一个强大的安全