本章开始讲解套接字API。

套接字地址结构

IPv4套接字地址结构

它以sockaddr_in命名,下面给出它的POSIX定义

struct in_addr
{
in_addr_t s_addr;
}; stuct sockaddr_in
{
uint8_t sin_len;
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[];
};

POSIX规范只需要这个结构中的3个字段:sin_family、sin_port和sin_addr。

下图列出了POSIX定义的关于socket编程的数据类型

通用的套接字地址结构

为了解决任意套接字地址结构都可以传递进使用套接字地址的套接字函数中,定义了一个通用的套接字地址结构。

任何套接字地址结构的指针都通过类型强制转换(变成通用套接字地址结构的指针)来做为函数参数。

通用的套接字地址结构如下所示

struct sockaddr
{
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[];
};

IPv6套接字地址结构

struct in_addr
{
in_addr_t s_addr;
}; struct sockaddr_in
{
uint8_t sin_len;
sa_family_t sin_family; /* AF_INET6 */
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[];
};

字节排序函数

网络字节序采用大端字节序,而不同主机使用不同的字节序。

下面4个函数用于主机字节序和网络字节序之间的相互转换

#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
//均返回:网络字节序的值;
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
//均返回:主机字节序的值;

h代表host,n代表network,s代表short,l代表long。

字节操纵函数

下面函数用于字节的设置、复制和比较。

#include <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
void bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
//返回:相等则为0,否则为非0
#include <string.h>
void *memset(void *dest, int c, size_t nbytes);
void *memcpy(void *dest, const void *src, size_t nbytes);
int memcmp(const void *s1, const void *s2, size_t nbytes);
//返回:相等则为0,否则为非0

函数inet_aton、inet_addr和inet_ntoa

这几个函数用于在点分十进制数串(如“206.168.112.96”)于它长度为32位的网络字节序二进制值间转换IPv4地址。

#include <arpa/inet.h>
int_addr_t inet_addr(const char *strptr);
//已被舍弃,使用inet_aton函数代替
int inet_aton(const char *strptr, struct in_addr *addrptr);
//返回:字符串有效返回1,否则为0
char *inet_ntoa(struct in_addr inaddr);
//返回:指向一个点分十进制的字符串的指针

函数inet_pton和inet_ntop

相对于上面的几个函数,这两个函数对于IPv4地址和IPv6地址都适用

#include <arpa/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr);
//返回:若成功返回1,输入不是有效表达格式返回0,若出错返回-1
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
//返回:若成功则返回指向结果的指针,出错则为NULL

p代表表达(presentation)  n代表数值(numeric)

family参数既可以是AF_INET,也可以是AF_INET6。

inet_pton尝试转换由strptr指针指向的字符串,并通过addrptr指针存放二进制结果。

inet_ntop进行相反的转换,len参数是目标储存单元的大小,以免该函数一处其调用者的缓冲区。对此,<netinet/in.h>头文件中由如下定义:

#define INET_ADDRSTRLEN            16
#define INET6_ADDRSTRLEN 46

UNP中定义的几个函数

inet_ntop函数的一个基本问题是:要求调用者必须知道这个结构的格式和地址族

我们可以使用自己定义的sock_ntop函数来解决这个问题

#include "unp.h"
char *sock_ntop(const struct sodkaddr *sockaddr, socklen_t addrlen);

该函数内部使用sockaddr指针来确定地址族,然后调用inet_ntop。

同样的,我们为操作套接字地址结构定义了如下几个函数

readn、writen和readline函数

字节流套接字(例如TCP套接字)上read和write函数所表现的行为不同于通常的文件

字节流套接字上调用read或write输入或输出的字节数可能比请求的数量少,然而这不是出错的状态,此时所需的是调用者再次调用read或write函数,以输入或输出剩余的字节。

我们提供一下3个函数是每当我们读或写一个字节流套接字时总要使用的函数

#include "unp.h"
ssize_t readn(int filedes,void *buff,size_t nbytes);
ssize_t writen(int filedes,const void *buff,size_t nbytes);
ssize_t readline(int filedes,void *buff,size_t nbytes);
//返回值:读或写的字节数,若出错则为-1

readn实现代码

 #include "unp.h"
ssize_t readn(int fd,void *vptr,size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr; ptr = vptr;
nleft = n;
while(nleft > )
{
if((nread = read(fd,ptr,nleft)) < )
{
if(errno == EINTR)
{
nread = ;
}
else
{
return -;
}
}
else if(nread == )
{
break;
}
nleft -= nread;
ptr += nread;
}
return (n-nleft);
}

writen实现代码

 #include "unp.h"
ssize_t written(int fd,void *vptr,size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while(nlfet > )
{
if((nwritten = writen(fd,ptr,nleft)) <= )
{
if(nwritten < && errno ==EINTR)
{
nwritten =;
}
else
{
return -;
}
} nleft -= nwritten;
ptr += nwritten;
}
return n;
}

readline实现代码

 #include "unp.h"
ssize_t readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n,rc;
char c,*ptr; ptr = vptr;
for(n = ; n < maxlen; n++)
{
if( (rc = read(fd, &c)) == )
{
*ptr ++ = c;
if(c == '\n')
break;
}
else if (r c== )
{
*ptr = ;
return (n-);
}else
return (-);
} *ptr = ;
return (n);
}

UNP学习笔记(第三章:套接字编程简介)的更多相关文章

  1. UNP学习笔记3——基本UDP套接字编程

    1 概述 TCP和UDP网络编程存在一些本质的差异,主要是由于传输层的差别:UDP是无连接的不可靠的数据报协议,而TCP是面向连接的字节流协议. 下图是典型的UDP客户端和服务器之间的通信流程.客户不 ...

  2. UNP学习笔记1——基本TCP套接字编程

    1 套接字地址结构 大多数套接字函数都需要一个指向套接字地址结构的指针作为参数.每个协议族都定义了自己的套接字结构.这些套接字的结构以sockaddr_开头,以每个协议族唯一的后缀名结尾. 1.1 I ...

  3. UNIX网络编程 第3章 套接字编程简介

    套接字结构类型和相关的格式转换函数

  4. 《DOM Scripting》学习笔记-——第三章 DOM

    <Dom Scripting>学习笔记 第三章 DOM 本章内容: 1.节点的概念. 2.四个DOM方法:getElementById, getElementsByTagName, get ...

  5. The Road to learn React书籍学习笔记(第三章)

    The Road to learn React书籍学习笔记(第三章) 代码详情 声明周期方法 通过之前的学习,可以了解到ES6 类组件中的生命周期方法 constructor() 和 render() ...

  6. [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设

    [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设 敲黑板!! <q>元素添加短引用,<blockquote>添加长引用 在段落里添加引用就使用< ...

  7. JVM学习笔记-第三章-垃圾收集器与内存分配策略

    JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...

  8. 【Unix网络编程】chapter3套接字编程简介

    chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...

  9. 【Unix网络编程】chapter3 套接字编程简介

    chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...

  10. UNP学习笔记(第二章:传输层)

    本章的焦点是传输层,包括TCP.UDP和SCTP. 绝大多数客户/服务器网络应用使用TCP或UDP.SCTP是一个较新的协议. UDP是一个简单的.不可靠的数据报协议.而TCP是一个复杂.可靠的字节流 ...

随机推荐

  1. POJ 3111 K Best(01分数规划)

    K Best Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 9876   Accepted: 2535 Case Time ...

  2. input聚焦时,滚动至可视区域

    这里的代码来自vux,觉得vux处理得很好,在此记录一下. 当我们在手机上填表单的时候,我们会希望正在填的input或者textarea会自动滚动至可视区域,方便我们边填写边查看内容.以前我的做法是, ...

  3. Python matplotlib 柱状图

    matplotlib是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中.它的文档相当完备,并且 ...

  4. response contentType

    response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据. 例如web浏览器就是通过MI ...

  5. 深入学习MongoDB

    NoSQL(Not Only SQL)为什么使用NoSQL 对数据库高并发读写 对海量数据的高效存储与访问 对数据库的高可拓展性和高可用性 NoSQL的弱点 数据库事务一致性需求 数据库的写实时性和读 ...

  6. 【CF1073C】Vasya and Robot(二分,构造)

    题意:给定长为n的机器人行走路线,每个字符代表上下左右走,可以更改将一些字符改成另外三个字符,定义花费为更改的下标max-min+1, 问从(0,0)走到(X,Y)的最小花费,无解输出-1 n< ...

  7. 【转】利用ScriptManager实现Javascript调用WebService中的方法

    原文发布时间为:2009-07-01 -- 来源于本人的百度文章 [由搬家工具导入] 前台调用后台方法,或者后台调用前台方法。ScriptManager实现 开发过程中,总想在前台直接调用后台的met ...

  8. Javascript中函数声明与函数表达式的不同

    定义函数的方式有两种:一种是函数声明,另一种是函数表达式. 函数声明的语法如下: function functionName(arg0,arg1,arg2){ //函数体 } 函数表达式的语法如下: ...

  9. Python 复习-1

    #!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2017/10/27 22:46 # @Author : lijunjiang # @Fi ...

  10. Scala 封装可break和continue的foreach循环

    发现scala里没有break和continue, 有时候实在是需要的话就要自己try catch异常,代码看起来有点蛋疼, 所以封装了一个可break和continue的foreach. impor ...