htonl() htons()及inet_ntoa() inet_addr()的用法

在写C/S模式的客户端服务端时经常遇到:主机序转网络序、网络序转主机序、十进制的IP转网络序、网络序转十进制IP。总是搞混,所以抽出点时间记录一下。

下面的代码是绑定socket的函数。

sockaddr_in addrin;
addrin.sin_family = AF_INET;
addrin.sin_port = htons(nport); //端口号
addrin.sin_addr.s_addr = inet_addr(szip);//ip地址 127.0.0.1
if(SOCKET_ERROR == bind(fd,(const sockaddr*)&addrin,sizeof(addrin)))
{
StopServer();
return false;
}


这里我先给点分十进制、主机序和网络序的关联:

用IP地址127.0.0.1为例:

第一步   127     .         0         .         0         .        1                 把IP地址每一部分转换为8位的二进制数。

第二步 01111111     00000000     00000000     00000001      =   2130706433   (主机字节序)

然后把上面的四部分二进制数从右往左按部分重新排列,那就变为:

第三步 00000001     00000000     00000000    01111111        =   16777343        (网络字节序)

如果上面的主机序和网络序的直观转换不明白原理的话,那你应该先了解一下 “ 大小端转换 ”。

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

因为我们的操作系统有一部分是用小端模式的,也有用大端模式的,即主机序可能为大端模式或小端模式,如果两台电脑存储模式不一样,会造成传输接收数据时存储混乱,所以为了保证传输接收数据时存储不至于混乱,TCP/IP规定网络传输数据时采用大端模式,网络字节序采用大端模式。


先放出函数:

htons()  -->将unsigned short 类型 从主机序转到网络序 --------此函数常用到处理端口号   addrin.sin_port = htons(nport); //端口号

ntohs()  -->将unsigned short 类型 从网络序转到主机序 

htonl()   -->将unsigned long类型 从主机序转到网络序    --------此函数常用到处理ip

ntohl()  -->将unsigned long类型 从网络序转到主机序


inet_addr(”192.0.0.1”)  -->将点分十进制IP转为长整型数(u_long类型) 

 ----------它转换出来的长整型数其实是网络序,如果想要得到是主机序可以这样ntohl( inet_addr("192.0.0.1") )


inet_ntoa()   -->将长整型数(u_long类型) 转为点分十进制     

----------它就是将网络序转为十进制,如果我们只知道主机序的话,可以先将主机序转为网络序,再用主机序转为点分十进制,即为这样:inet_ntoa( htonl(主机序) )


char szbuf[1024] = {0};
hostent  *phosttent = NULL;
struct in_addr addr;

if(!gethostname(szbuf,1024))     //获取主机名
{
phosttent = gethostbyname(szbuf);    //通过主机名的
if(phosttent->h_addr_list[0])          //返回对应于给定主机名的包含主机名字和地址信息的hostent结构的指针
{
addr.s_addr = *(u_long *) phosttent->h_addr_list[0];     //得到本机的第一个ip(自己的电脑同一时间可能会有好几个ip)
m_IPaddress.SetAddress(ntohl(addr.s_addr) );     //MFC中一个显示IP的控间             
}
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>int main() { int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建套接字 if (server_socket < 0) { perror("socket"); return 1; } struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(8000); int iResult = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 绑定套接字 if (iResult < 0) { perror("bind"); close(server_socket); return 1; } iResult = listen(server_socket, SOMAXCONN); // 监听套接字 if (iResult < 0) { perror("listen"); close(server_socket); return 1; } printf("服务器已启动,等待连接...\n"); int counter = 0; while (1) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len); // 接受客户端连接 if (client_socket < 0) { perror("accept"); close(server_socket); return 1; } counter++; // 每当有一个新的客户端连接时,计数器加1 printf("客户端 %s:%d 已连接,是今天的第 %d 个客户端。\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), counter); char reply[1024]; sprintf(reply, "你是今天第%d个客户端", counter); send(client_socket, reply, strlen(reply), 0); // 发送回复消息 close(client_socket); } close(server_socket); return 0;},在此代码基础上增加输出当前时间的功能
最新发布
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值