socket概述和字节序、地址转换函数
一、什么是socket
socket可以看成是用户进程与内核网络协议栈的编程接口。
socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及以后要讲的UNIX Domain Socket。然而,各种网络协议的地址格式并不相同,如下图所示:
IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,如下所示:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
char sin_zero[8]; /* pad bytes, set to zero is ok */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
IPv6地址用sockaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。UNIX Domain Socket的地址格式定义在sys/un.h中,用
sockaddr_un结构体表示。各种socket地址结构体的开头都是相同的,对于unix 的某些实现来说 前8位表示整个结构体的长度,后8位表示地址类型,
而Linux就没有长度字段,前2个字节都是地址类型。IPv4、IPv6和UNIX Domain Socket的地址类型分别定义为常数AF_INET、AF_INET6、
AF_UNIX。 这样,只要取得某种sockaddr 结构体的首地址,不需要知道具体是哪种类型的sockaddr 结构体,就可以根据地址类型字段确定结构体中
的内容。因此,socket API可以接受各种类型的 sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *
类型以便接受各种类型的指针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表
示,即通用地址结构,如下所示:
struct sockaddr {
sa_family_t sin_family;
char sa_data[14];
};
sin_family:指定该地址家族
sa_data:由sin_family决定它的形式。
在传递参数之前要强制类型转换一下,例如:
struct sockaddr_in servaddr;
/* initialize servaddr */
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
二、网络字节序
字节序
大端字节序(Big Endian)
最高有效位(MSB:Most Significant Bit)存储于最低内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最高内存地址处。
小端字节序(Little Endian)
最高有效位(MSB:Most Significant Bit)存储于最高内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最低内存地址处。
主机字节序
不同的主机有不同的字节序,如x86为小端字节序,Motorola 6800为大端字节序,ARM字节序是可配置的。
网络字节序
网络字节序规定为大端字节序
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
下面写个小程序测试下主机的大小端:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/*************************************************************************
> File Name: byteorder.c > Author: Simba > Mail: dameng34@163.com > Created Time: Fri 01 Mar 2013 04:16:08 PM CST ************************************************************************/ #include<stdio.h> int main(void) unsigned int y = htonl(x); return 0; |
输出为:
simba@ubuntu:~/Documents/code/linux_programming/UNP/socket$ ./byteorder
78 56 34 12
12 34 56 78
即本主机是小端字节序,而经过htonl 转换后为网络字节序,即大端。
三、地址转换函数
前面提到的 sockaddr_in 结构体中的成员struct in_addr sin_addr表示32位的IP地址。但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换。
字符串转in_addr的函数:
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);
注意,转换而成的32位数是网络字节序的。
in_addr转字符串的函数:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
注意,传入的32位数也是网络字节序的。
其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void *addrptr。
下面写个小程序演示一下:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/*************************************************************************
> File Name: addr_in.c > Author: Simba > Mail: dameng34@163.com > Created Time: Fri 01 Mar 2013 04:16:08 PM CST ************************************************************************/ #include<stdio.h> int main(void) unsigned int addr = inet_addr("192.168.0.100"); //转换后是网络字节序(大端) struct in_addr ipaddr; return 0; |
输出为:
simba@ubuntu:~/Documents/code/linux_programming/UNP/socket$ ./addr_in
add=3232235620
192.168.0.100
注意,在打印addr的时候先转换成主机字节序。
四、套接字类型
流式套接字(SOCK_STREAM)
提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。
数据报式套接字(SOCK_DGRAM)
提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。
原始套接字(SOCK_RAW)
参考:
《Linux C 编程一站式学习》
《TCP/IP详解 卷一》
socket概述和字节序、地址转换函数的更多相关文章
- TCP和UDP的区别与联系以及网络字节序和主机字节序的转换函数实践
TCP和UDP的区别 TCP是一个面向连接的.可靠的.基于字节流的传输层协议. 而UDP是一个面向无连接的传输层协议. 具体来分析,和 UDP 相比,TCP 有三大核心特性: 面向连接:所谓的连接,指 ...
- UNIX网络编程——socket概述和字节序、地址转换函数
一.什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口.socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信. socket API是一层抽象的网络 ...
- c# 主机和网络字节序的转换 关于网络字节序和主机字节序的转换
最近使用C#进行网络开发,需要处理ISO8583报文,由于其中有些域是数值型的,于是在传输的时候涉及到了字节序的转换. 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有两种字节顺序, ...
- 【网络编程一】主机字节序与网络字节序以及ip地址转换函数
在计算机设计之初,对内存中数据的处理也有不同的方式,(低位数据存储在低位地址处或者高位数据存储在低位地址处),然而,在通信的过程中(ISO/OSI模型和TCP/IP四层模型中),数据被一步步封装(然后 ...
- Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)
IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...
- Socket中常见的几个转换函数(htonl,htons,ntohl,ntohs,inet_addr,inet_ntoa)
Socket中常见的几个转换函数(htonl,htons,ntohl,ntohs,inet_addr,inet_ntoa) htonl() htons() ntohl() ntohs()及inet_n ...
- 地址转换函数:inet_aton & inet_ntoa & inet_addr和inet_pton & inet_ntop
在Unix网络编程中,我们常用到地址转换函数,它将ASCII字符串(如"206.62.226.33")与网络字节序的二进制值(这个值保存在套接口地址结构中)间进行地址的转换. 1. ...
- socket编程基础-字节序/IP/PORT转换/域名
socket编程基础 网络IP操作函数 字符串的IP和32位的IP转换 #include <sys/socket.h> #inlcude <netinet/in.h> #inc ...
- IP地址转换函数——inet_pton inet_ntop inet_aton inet_addr inet_ntoa
inet_pton NAME inet_pton - 将 IPv4 和 IPv6 地址从点分十进制转换为二进制 SYNOPSIS #include <arpa/inet.h> in ...
随机推荐
- Combinations leetcode java
题目: Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For ex ...
- IOS中的动画——Core Animation
一.基础动画 CABasicAnimation //初始化方式 CABasicAnimation * cabase=[CABasicAnimation animation]; //通过keyPath设 ...
- 县级以上联动js实现无需数据库的行政区域下拉控件
代码共享url: http://code.google.com/p/region-select-js/ 数据已经更新到中国统计局网站中的2012年的那批数据(制作后未核对); 下拉使用div模拟实现. ...
- TreeListControl 不同类别的行使用不同的数据模板
- IE与Cognos的那些事
问题描述1:打开报表设计页面的时候,即打开reportstudio的时候报IE阻止了一个来自XX.XX.XX.XX的弹出窗口程序 IE设置:关闭弹出窗口阻止程序即可 问题描述2:无法下载文件,例如Ex ...
- Tomcat7出现HTTP Status 500 - java.lang.ClassCastException: org.apache.jasper.el.ELContextImpl cannot be cast to org.apache.jasper.el.ELContextImpl的解决
今天在Tomcat7上发布了一个war,过一阵子发现localhost:8080都进不去了.在浏览器输入http://localhost:8080出现如下内容: HTTP Status 500 - j ...
- jQuery和CSS3超酷表单美化插件
这是一款效果很精美炫酷的jQuery和CSS3联系方式表单美化插件.大多数站点上都有让用户填写的联系方式表单,一个设计良好的表单可以大大的提升用户的体验度.该表单美化插件在原生HTML表单的基础上进 ...
- 字段计算器VBS
ArcGIS属性表中右键可调用字段计算器.写一些简单代码可操作属性表,有VBS和Python两种. 现在要求是:如果"地块编码"为空,则将"地块编号"赋给&qu ...
- static 和 no static Member function学习
以下是做实验的一段代码: #include <iostream> using namespace std; typedef void (*p)(); class Object { publ ...
- vb sendmessage 详解1
SendMessage函数的常用消息及其应用(有点长,希望能对大家有所帮助)函数原型: Declare Function SendMessage Lib "user32" Alia ...