文档章节

网络编程学习——套接字编程(一)

thanatos_y
 thanatos_y
发布于 2016/04/09 17:06
字数 1591
阅读 21
收藏 1

1 套接字地址结构

  大多数套接字函数需要一个指向套接字地址结构的指针作为参数。每个协议族都定义它自己的套接字地址结构。这些结构的名字均以是sockaddr_开头,并以对应每个协议族的唯一后缀结尾。

 1.1 IPv4套接字地址结构

  IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中。__SOCKADDR_COMMON宏定义在<bits/sockaddr.h>。sockaddr定义在/usr/include/bits/socket.h中。 当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递,然而以这样的指针作为参数之一的任何套接字函数必须处理来自所支持的任何协议族的套接字地址结构。

/* POSIX.1g specifies this type name for the `sa_family' member.  */
typedef unsigned short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */
#define    __SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

  
/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    /* Common data: address family and length.  */
    char sa_data[14];        /* Address data.  */
  };
  
  
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr; //32位的IPv4地址
  };
  
/* Type to represent a port.  */
typedef uint16_t in_port_t;
/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);     /* 协议族 */
    in_port_t sin_port;            /* Port number. 端口号 */
    struct in_addr sin_addr;        /* Internet address. IP地址 */

    /* Pad to size of `struct sockaddr'. 用于填充0的字节 */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

 

  二者的占用的内存大小是一致的,因此可以互相转化,从这个意义上说,他们并无区别。

  sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息。是一种通用的套接字地址。而 sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作。使用sockaddr_in来建立所需的信 息,最后使用类型转化就可以了。下面是一个完整的例子。

 

 1.2 IPv6套接字地址结构

/* IPv6 address */
struct in6_addr
  {
    union
      {
    uint8_t    __u6_addr8[16];
#if defined __USE_MISC || defined __USE_GNU
    uint16_t __u6_addr16[8];
    uint32_t __u6_addr32[4];
#endif
      } __in6_u;
      
/* Ditto, for IPv6.  */
struct sockaddr_in6
  {
    __SOCKADDR_COMMON (sin6_);
    in_port_t sin6_port;    /* Transport layer port # */
    uint32_t sin6_flowinfo;    /* IPv6 flow information */
    struct in6_addr sin6_addr;    /* IPv6 address */
    uint32_t sin6_scope_id;    /* IPv6 scope-id */
  };

 1.3 套接字地址结构的比较

  在图1-1中,我们对本书遇到的5种套接字地址结构进行了比较:IPv4、IPv6、Unix域、数据链路和存储。在该图中,我们假设所有套接字地址结构都包含一个单字节的长度字段,地址族字段也用一个字节,其他所有字段都站用确切的最短长度。

  前两种套接字地址结构是固定长度的,而Unix域结构和数据结构是可变长的。为了处理长度可变的结构,当我们把指向某个套接字地址结构的指针作为一个参数传递给某个套接字函数时,也把该结构的长度作为另一个参数传递给这个函数。我们在每种长度固定的结构下方给出了这种结构的字节数长度。

图1-1 不同的套接字地址结构

 1.4 值-结果参数

  套接字结构长度页也作为一个参数来传递,不过其传递方式取决于该结构的传递方向:是从进程到内核,还是内核到进程。

 (1)从进程到内核传递套接字地址结构的函数有3个:bind、connect和sendto。这些函数的一个参数是指向某个套接字地址结构的指针,另一个参数是该结构的整数大小。例如,

struct sockaddr_in addr;
connect( sockfd, (struct sockaddr*)&addr, sizeof(addr) );

  既然指针和指针所指内容的大小都传递给了内核,于是内核直到到底需要从进程复制多少数据进来。图1-2展示了这个情形。

图1-2 从进程到内核传递套接字地址结构

 (2)从内核到进程传递套接字地址结构的函数有4个:accept、recvfrom、getsockname和getpeername。这4个函数的其中两个参数是指向某个套接字地址结构的指针和指向表示该结构大小的整数变量的指针。例如,

struct sockaddr_in addr;
socklen_t len = sizeof(addr);

getpeername( sockfd, (struct sockaddr*)&addr, &len );

  把套接字地址结构大小这个参数从一个整数改为指向某个整数变量的指针,其原因在于:当函数被调用时,结构大小是一个值(value),它告诉内核该结构的大小,这样内核在写该结构时不至于越界;当函数返回时,结构大小又是一个结果(result),它告诉进程内核在该结构中究竟存储了多少信息。这种类型的参数称为值-结果(value-result)参数。图1-3展示了这个情形。

图1-3 从内核到进程传递套接字地址结构

 

 1.5 字节排序函数

  考虑一个16位整数,它由2个字节组成。内存中存储这两个字节有两种方法:一种是将低字节存储在起始地址,这称为小端(little-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。图1-4展示了这两种格式。

图1-4 16位整数的小端字节序和大端字节序

  在该图中,我们在顶部表明内存地址增长的方向为从右到左,在底部标明内存地址增长的方向为从左到右。我们还表明最高有效位(most significant bit,MSB)是这个16位值最左边一位,最低有效位(least significant bit,LSB)是这个16位值最右边一位。

  遗憾的是,这两种字节序之间没有标准可循,两种格式都有系统使用。我们把某个给定系统所用的字节序称为主机字节序(host byte order)。网络协议必须指定一个网络字节序(network byte order)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

thanatos_y
粉丝 7
博文 112
码字总数 315059
作品 0
成都
程序员
私信 提问
0-Linux 网络编程修炼指南——内功心法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1007729991/article/details/69091877 学习交流群: Linux 学习交流群 610441700 说明:本系列文章并不能取代...

--Allen--
2017/04/04
0
0
Python网络编程—第26课—Socket原理简介(0531)

一、Python网络编程——客户端/服务器架构 1、服务器:服务器就是一系列硬件和软件,为一个或多个客户端提供所需要的服务。存在的目的就是等待客户端的请求,并响应他它们,然后等待更多请求...

python初雪之路
2018/05/29
22
0
Linux网络编程——原始套接字能干什么?

版权声明:本博客文章,大多是本人整理编写,或在网络中收集,转载请注明出处! https://blog.csdn.net/tennysonsky/article/details/44655077 通常情况下程序员接所接触到的套接字(Socket)...

Mike__Jiang
2015/03/26
0
0
再读Socket编程——《UNIX网络编程(卷一)》学习点滴

  原先曾以Socket编程为入口开始自己的新的学习,毕竟未曾致用,时至今日已比较生疏。借着阅读《UNIX网络编程(卷一)》(简称UNPv1)的机会,正好复习一番,而且希望将新的感受记录下来。...

长征6号
2017/04/12
0
0
socket网络编程之TCP、UDP

之前说的用于进程间通信的几种方式:消息signal、管道pipe、消息队列msg、共享内存shm、信号量sem。都只适用于一台主机上的进程间通信,那么如何实现两台计算机之间的进程通信呢?所以,来了...

SherryX
2018/06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
6
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0
Docker容器实战(七) - 容器中进程视野下的文件系统

前两文中,讲了Linux容器最基础的两种技术 Namespace 作用是“隔离”,它让应用进程只能看到该Namespace内的“世界” Cgroups 作用是“限制”,它给这个“世界”围上了一圈看不见的墙 这么一...

JavaEdge
今天
8
0
文件访问和共享的方法介绍

在上一篇文章中,你了解到文件有三个不同的权限集。拥有该文件的用户有一个集合,拥有该文件的组的成员有一个集合,然后最终一个集合适用于其他所有人。在长列表(ls -l)中这些权限使用符号...

老孟的Linux私房菜
今天
7
0
面试套路题目

作者:抱紧超越小姐姐 链接:https://www.nowcoder.com/discuss/309292?type=3 来源:牛客网 面试时候的潜台词 抱紧超越小姐姐 编辑于 2019-10-15 16:14:56APP内打开赞 3 | 收藏 4 | 回复24 ...

MtrS
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部