关于Socket通信过程中字节序

在网络编程里,网络字节序是big-endian的,而大部分的PC的系统都是X86处理器系列,X86采用的是little-endian,所以需要将网络数据流转换成本地数据流的话,需要进行字节序的转换。

标准库里提供了hlton()和nthl()两个函数来支持转换。

hston(unsigned short), hlton(unsigned long)  将本地字节序转换为网络字节序

ntohl(unsigned long), ntohs(unsigned short)  将网络字节序转换为本地字节序

但是对于64位的整数进行转换,标准库并没有提供相应的转换函数。

关于本系统是Big-endian还是Little-endian存储,可以写一个简单函数进行判断:

#include<stdio.h>
int main(){int num = 0x1234;int* p = &num;if(*((char*)p) == 0x12){printf("Big-endian\n");}else{printf("Little-endian\n");}return 0;
}

另外,关于socket通信过程中客户端和服务端操作系统位数的问题,本人在Vmware中开启了三个Ubuntu(两个为32位操作系统,一个为64位操作系统,皆为小端存储),以一个32位系统运行socket通信的客户端,另外两个设置为服务端,通过修改客户端的访问目标ip地址观察不同位系统socket通信结果,发现32to32,一切正常可以运行,程序命令行传入参数可以顺利达到服务端经服务端数据处理函数处理之后返回至客户端并打印出来,期间在服务端打印出客户端传送过来的数据并打印客户端的地址、端口信息。

但在32to64通信过程中,服务端显示乱码,且不能正常返回处理后的数据。

查阅资料:在32位机器和64机器中int类型都占用4个字节。编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。 
这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节,总体而言,最大的不同点就是在long型和指针类型长度不一样,对于指针而言,64位机器可以寻址2^64,每个内存地址长度为64位,即8字节。

服务端程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAX_LINE 100
/* 处理函数,用于将大写字符转换为小写字符。参数为需要转换的字符串 */
void my_fun(char * p)
{if(p == NULL)                 /* 空串 */return;for (; *p != '\0'; p++)if(*p >= 'A' && *p <= 'Z') /* 判断字符并进行转换,也可以使用库函数 */*p = *p -'A' + 'a';
}
int main(void)
{struct sockaddr_in sin;struct sockaddr_in cin;int l_fd;int c_fd;socklen_t len;char buf[MAX_LINE];                  /* 存储传送内容的缓冲区 */char addr_p[INET_ADDRSTRLEN];       /* 存储客户端地址的缓冲区 */int port = 8000;                  /* 端口号,使用8000 */int n;                               /* 读写字节数 */bzero(&sin, sizeof(sin));            /* 清空地址结构 */sin.sin_family = AF_INET;          /* 使用IPv4通信域 */sin.sin_addr.s_addr = INADDR_ANY;   /* 服务器可以接受任意地址 */sin.sin_port = htons(port);       /* 端口号转换为网络字节序 */l_fd = socket(AF_INET, SOCK_STREAM, 0); /* 创立套接字,使用TCP协议 */bind(l_fd, (struct sockaddr*) &sin, sizeof(sin)); /* 将地址和套接字绑定 */listen(l_fd, 10);                      /* 开始监听连接请求 */printf("waiting ...\n");while(1){/* 服务器程序多半是死循环 *//* 接受连接请求,从此函数中返回后就可以开始通信了 */c_fd = accept(l_fd, (struct sockaddr*) &cin, &len); n = read(c_fd, buf, MAX_LINE);  /* 读取客户端传来的信息 *///inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p));/* 将客户端地址转换为字符串 *///printf("client IP is %s, port is %d\n", addr_p, ntohs(cin.sin_port));                                             /* 打印客户端地址和端口号 */printf("content is : %s\n", buf);    /* 打印客户端发送过来的字符串 */my_fun(buf);                     /* 调用大小写转换函数 */write(c_fd, buf, n);             /* 将转换后的字串发给客户端 */close(c_fd);          /* 通信结束,关闭套接字,准备下一次通信 */}if(close(l_fd) == -1){     /* 通信结束,关闭套接字,准备下一次通信 */perror("fail to close");exit(1);}return 0; /* 不应该执行到这里 */
}

客户端程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#define MAX_LINE 100int main(void)
{struct sockaddr_in sin;char msg[100];int l_fd;char buf[MAX_LINE];                                     /* 存储传送内容的缓冲区 */int port = 8000;                                       /* 端口号,使用8000 */bzero(&sin, sizeof(sin));                       /* 清空地址结构 */sin.sin_family = AF_INET;                       /* 使用IPv4通信域 */inet_pton(AF_INET,"10.17.38.98", &sin.sin_addr);sin.sin_port = htons(port);             /* 端口号转换为网络字节序 */l_fd = socket(AF_INET, SOCK_STREAM, 0); /* 创立套接字,使用TCP协议 */connect(l_fd, (const struct sockaddr*)&sin, sizeof(sin));printf("Input Message:\n");scanf("%s", msg);write(l_fd, msg, strlen(msg)+1);sleep(5); //延时读取read(l_fd, buf, MAX_LINE);printf("Receive messaege from server: %s\n", buf);//close(l_fd);if(close(l_fd) == -1){          /* 通信结束,关闭套接字,准备下一次通信 */perror("Fail to close !");exit(1);}return 0;
}

对64位服务端的server.c程序屏蔽掉客户端IP、端口获取并打印的相关代码段,此时服务端、客户端均能能够正常运行。因此,在char型命令行参数传递过程中是没有问题的,32位和64位操作系统的主要区别在于指针以及结构体(内存对齐位数不同),而accept()的第二个参数是客户端的地址结构,由客户端的connect()函数发送给服务端,在这过程中存在位数不匹配的问题,因此不能进行正常通信。

另,根据上述原理,可以声明一个空类型指针用来判断系统的位数。

#include<iostream>int main(){void* p;if(sizeof(p)==4){std::cout << "This is a 32-bit machine."  << std::endl;}else std::cout << "This is a 64-bit machine." << std::endl;return 0;
}

在32位和64位系统测试结果如下:

Socket通信之操作系统的字节序和位数相关推荐

  1. 1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

     1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端 ...

  2. 通信大小端字节序相关问题总结

    [备注:本文主要是将最新box项目中,遇到的问题做以总结梳理,便于加深印象和后续查阅.本文相关资料主要来源于网络,包括转载的一些资料] 遇到问题: 1.何为大.小端存储. 2.若协议中提及" ...

  3. api有哪些 javasocket_Java的socket通信与操作系统的SocketAPI关系探究

    Java使用Socket的通信过程 1.服务器端socket绑定端口,并一直监听该端口,等待客户端的连接 2.客户端绑定一个端口,并通过套接字连接服务器端等待服务的端口 3.连接成功后,服务器端和客户 ...

  4. linux c 客户端与 golang 服务端通信(网络字节序)

    网络二进制数据转换: 总所周知,数据在tcp网络传输协议中传输的字节序是大端模式的,换句话说如果你要传输一个int32型的整数,那么假设其二进制小端模式表示为111111111111111100000 ...

  5. Android与物联网设备通信-自定义报文与字节序

    前几节我们把网络通信中的基础都过了一遍,今天真正开始秀操作了.本节主要讲解如何在应用层上去定义报文的结构体.良好的报文设计会让今后的业务扩展变得轻松.顺带会讲解一下字节序. 可以发现最近的章节都把两个 ...

  6. Linux C++服务器项目——网络编程1 (socket通信,服务端,客户端)

    牛客 C++高并发服务器开发 参考笔记 1.MAC地址 2 IP地址 2.1 简介 2.2 IP地址编址方式 2.3 子网掩码 3 端口 3.1 简介 3.2 端口类型 4 网络模型 4.1 OSI七 ...

  7. 网络字节序 —— 主机字节序 (Socket编程) 转

    在对IP地址结构体SOCKADDR_IN赋值的时候,经常会用到下列的函数htonl,htons,inet_addr,与之相对应的函数是ntohl,ntohs,inet_ntoa.查看这些函数的解析,会 ...

  8. OSI七层、TCP/IP五层、UDP、TCP的socket编程(服务端及客户端)、字节序转换、多进程以及多线程服务端的实现

    1.网络以覆盖范围划分:局域网/城域网/广域网   互联网/因特网   以太网/令牌环网--组网方式 2.在网络中必须能够为一表示每一台主机,才能实现点到点的精确通信            IP地址: ...

  9. 【Socket网络编程】3.字节序转换函数htons、htonl ,地址转换函数inet_ntoa、inet_ntop、inet_pton、inet_addr

    字节序转换函数htons.htonl 地址转换函数inet_ntoa.inet_ntop.inet_pton.inet_addr 1.字节序转换函数 #include <arpa/inet.h& ...

最新文章

  1. 杨超越第一,Python第二
  2. UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: encoding error
  3. selenium根据文本匹配定位
  4. SourceTree跳过Atlassian账号,免登陆,跳过初始设置
  5. 你有必要知道的一些JavaScript 面试题(中)
  6. pytorch 转换onnx_新版PyTorch发布!新增TorchScript API,扩展ONNX导出
  7. antd 3升级命令_是时候拥有一个你自己的命令行工具了
  8. 疯狂java workflow_疯狂Workflow讲义:基于Activiti的工作流应用开发 完整pdf扫描版[136MB]...
  9. 第一个hadoop 程序
  10. 可怕!CPU 竟成了黑客的帮凶!
  11. 自学python能干些什么副业-她把摄影当副业:月薪3000,副业收入上万
  12. 新手学编程的常见困惑
  13. oracle的lpad函数
  14. PO:通过Floder限制订单汇总中采购单价及金额栏位
  15. 庄周带你练习数据库语句复习常备之【JavaWeb阶段学习】
  16. 趣图:万一跑路失败被抓,可以这样解释
  17. BUUCTF-网鼎杯2020-青龙组-joker
  18. 文件传输协议——FTP概述
  19. 【python】机器学习算法(KNN)入门——手写数字识别
  20. 创客匠人产品怎么样?

热门文章

  1. 2021年大数据ELK(二十六):探索数据(Discovery)
  2. 2021年大数据Hadoop(三十):Hadoop3.x的介绍
  3. 2021年大数据Spark(二十三):SparkSQL 概述
  4. C++ map 的使用
  5. Android AnimationUtils (动画)的使用
  6. 一些js代码,自己备用的。高手不要笑话我。。(跨浏览器基础事件,浏览器检测,判断浏览器的名称、版本号、操作系统)...
  7. 第16届信息安全与对抗技术竞赛-Misc
  8. Linux-CentOS 查看(监控)服务器网卡流量
  9. private关键字和构造方法
  10. Laravel安装后没有vendor文件夹