第十六章(一) 套接字初识

2024-06-22 20:08
文章标签 接字 初识 第十六章

本文主要是介绍第十六章(一) 套接字初识,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!



地址格式
 一个地址标识一个特定通信域的套接字端点,地址格式与这个特定的通信域相关。为使不同的格式地址能够传入到套接字函数,地址会被强制转化成一个通用的地址结构:

struct sockaddr{sa_family_t  sa_family;   //address familychar   sa_data[];   //variable-length address...
};


 在IPv4因特网域(AF_INET)中, 套接字结构地址用以下结构表示:

struct in_addr{in_addr_t  s_addr;  //IPv4 address
};struct sockaddr_in{sa_family_t sin_family; //address familyin_port_t sin_port; //port numberstruct in_addr_t sin_addr; //IPv4 address
};


 最终将转化为结构体 sockaddr 输入到套接字例程中。


有两个函数用于将地址格式进行转换

char *inet_ntop(int domain, void *addr, char *str, socklen_t size)//用于将网络字节序的二进制地址转化成文本字符串格式
char *inet_pton(int domain, char *str, void *addr)//用于将文本字符串格式转换成网络字节序的二进制地址。



地址查询

<span style="color:#000000;">struct hostent *gethostent(void);//可以找到给定计算机系统的主机信息
struct netent *getnetent(void);//获取网络编号和网络名字</span>



 我们可以用以下函数在协议名字和协议编号之间进行映射

struct protoent *getprotobyname(char * name);
struct protoent *getprotobynumber(int proto);
struct protoent *getprotoent(void);


 各服务和端口号之间的关系

struct servent *getservbyname(char *name, char *proto)//将一个服务名映射到一个端口号 
struct servent *getserbyport(int pert, char *name)//将一个端口号映射到一个服务名
struct servent *getservent(void);//顺序扫描服务数据库


int getaddrinfo(char *host, char *service, struct addrinfo *hint, struct addrinfo **resg)//用于将一个主机名和一个服务名映射到一个地址//可以提供一个可选的hint来选择符合特定条件的地址

  如果getaddrinfo调用失败,不能使用perror或strerror来生成错误信息,而是调用
   函数 char *gai_strerror(int error)    
  如果本函数返回成功,那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以导致返回多个addrinfo结构的情形有以下2个:
   1. 如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。
   2. 如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。


 函数 getnameinfo将一个地址转换成一个主机名和一个服务名

 以下两个程序说明 getaddrinfo 的使用方法:

                       注:总是显示bind错误,尚未搜出个明白来。

例一:

#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n",
argv[1]);
exit(1);   
}struct addrinfo *answer, hint, *curr;
char ipstr[16];   
bzero(&hint, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;int ret = getaddrinfo(argv[1], NULL, &hint, &answer);
if (ret != 0) {
fprintf(stderr,"getaddrinfo: &s\n",
gai_strerror(ret));
exit(1);
}for (curr = answer; curr != NULL; curr = curr->ai_next) {
inet_ntop(AF_INET,
&(((struct sockaddr_in *)(curr->ai_addr))->sin_addr),
ipstr, 16);
printf("%s\n", ipstr);
}
freeaddrinfo(answer);
exit(0);
}

例二:

void print_family(struct addrinfo *aip);  
void print_type(struct addrinfo *aip);  
void print_flags(struct addrinfo *aip);  
void print_protocol(struct addrinfo *aip);  int main(int ac, char *av[])
{struct addrinfo *ailist, *aip;struct addrinfo hint;if(ac != 3)fprintf(stderr,"Usage : %s nodename service", av[0]);hint.ai_family = 0;    				//初始化hint结构体用于过滤hint.ai_socktype = 0;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_flags = AI_CANONNAME;			//需要一个规范名hint.ai_addr = NULL;    hint.ai_next = NULL;				hint.ai_canonname = NULL;if(getaddrinfo(av[1].av[2],&hint,&ailist) != 0)printf("%s \n",gai_strerror(error));for(aip=ailist; aip ; aip=aip->ai_next)				//打印得到的结果{print_family(aip);  print_type(aip);  print_protocol(aip);  print_flags(aip);  printf("\n\thost %s", aip->ai_canonname ?aip->ai_canonname:"-");  if(aip->ai_family == AF_INET)  {  /* 获取IP地址,并把网络字节序的二进制地址转换为文本字符串地址 */  sinp = (struct sockaddr_in *)aip->ai_addr;  addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf, INET_ADDRSTRLEN);  printf(" address %s", addr ? addr:"unknown");  printf(" port %d", ntohs(sinp->sin_port));  }  printf("\n");  }return 0;
}void print_family(struct addrinfo *aip)  
{  printf(" family-- ");  switch(aip->ai_family)  {  case AF_INET://IPv4  printf("inet");  break;  case AF_INET6://IPv6  printf("inet6");  break;  case AF_UNIX://UNIX域  printf("Unix");  break;  case AF_UNSPEC://未指定  printf("unspecified");  break;  default:  printf("unknown");  }  
}  
void print_type(struct addrinfo *aip)  
{  printf(" type.. ");  switch(aip->ai_socktype)  {  case SOCK_STREAM:  printf("stream");  break;  case SOCK_DGRAM:  printf("datagram");  break;  case SOCK_RAW:  printf("raw");  break;  case SOCK_SEQPACKET:  printf("seqpacket");  break;  default:  printf("unknown (%d)", aip->ai_socktype);  }  
}  void print_protocol(struct addrinfo *aip)  
{  printf(" protocol++ ");  switch(aip->ai_protocol)  {  case IPPROTO_TCP:  printf("TCP");  break;  case IPPROTO_UDP:  printf("UDP");  break;  case IPPROTO_SCTP:  printf("SCTP");  break;  case 0:  printf("default");  break;  default:  printf("unknown (%d)", aip->ai_protocol);  }  
}  
void print_flags(struct addrinfo *aip)  {  printf(" flags ");  if(aip->ai_flags == 0)  printf("0");  else  {  if(aip->ai_flags & AI_PASSIVE)  printf(" passive ");  if(aip->ai_flags & AI_CANONNAME)  printf(" canon ");  if(aip->ai_flags & AI_NUMERICHOST)  printf(" numhost ");  }  }  


将套接字与地址关联

int bind(int sockfd, struct sockaddr *addr, socklen_t len)//用来关联地址和套接字/*对于使用的地址有以下一些限制:1、在进程正在运行的计算机上,指定的地址必须有效; 不能指定一个其他机器的地址2、地址必须和创建套接字时的地址族所支持的格式相匹配3、地址中的端口号必须不小于1024,除非该进程具有相应的特权(root身份)4、一般只能将一个套接字端点绑定到一个给定地址上,尽管有些协议允许多重绑定*/

getsockname(int sockfd, struct sockaddr *addr, socklen_t alenp)//用来发现绑定到套接字上的地址/*在调用 getsockname之前, 将 alenp 设置为一个指向整数的指针。该整数指定缓冲区 sockaddr 的长度。 返回时, 该整数会被设置返回地址的大小。但是,如果地址和提供的缓冲区长度不匹配,地址会被自动截断而不报错。如果当前没有地址绑定到该套接字,结果是未定的。*/

getpeername(int sockfd, struct sockaddr *addr, socklen_t alenp)//如果套接字已经和对等方连接, 可以用来找到对方的地址。

 


建立连接

int connect(int sockfd, struct sockaddr *addr, socklen_t len)//在请求服务的进程套接字(客户端)和提供服务的进程套接字之间建立一个连接。//所填入的地址是我们想要与之通信的服务器地址。


监听套接字

int listen(int sockfd, int backlog)//用于宣告服务器愿意接受连接请求//一旦系统满,就会拒绝多余的连接请求,所以backlog的值应该基于服务器期望负载和处理量来选择,其中处理量是指接受连接请求与启动服务的数量。


获取套接字信息

int accept(int sockfd, struct sockaddr *addr, socklen_t len)/* 一旦服务器调用了listen, 所用的套接字就接收连接请求。使用 accept 函数获得连接请求并建立连接返回的文件描述符是连接到调用connect的客户端的套接字描述符如果服务器调用accept,并且当前没有连接请求,服务器会阻塞知道一个链接请求到来。另外,服务器可以调用 poll 或 select 来等待一个请求的到来*/




这篇关于第十六章(一) 套接字初识的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085285

相关文章

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

C语言入门系列:初识函数

文章目录 一,C语言函数与数学函数的区别1,回忆杀-初中数学2,C语言中的函数 二, 函数的声明1,函数头1.1,函数名称1.2,返回值类型1.3,参数列表 2,函数体2.1,函数体2.2,return语句 三,main函数四,函数的参数与传递方式1,实参和形参1.1,函数定义(含形参)1.2,函数调用(使用实参) 2,参数传递方式2.1,值传递2.2,引用传递 五,函数原型与预声明1,

任务5.1 初识Spark Streaming

实战概述:使用Spark Streaming进行词频统计 1. 项目背景与目标 背景: Spark Streaming是Apache Spark的流处理框架,用于构建可伸缩、高吞吐量的实时数据处理应用。目标: 实现一个实时词频统计系统,能够处理流式数据并统计文本中的单词出现频率。 2. 技术要点 Spark Streaming集成: 与Spark生态的其他组件如Spark SQL、ML

初识 SpringMVC,运行配置第一个Spring MVC 程序

1. 初识 SpringMVC,运行配置第一个Spring MVC 程序 文章目录 1. 初识 SpringMVC,运行配置第一个Spring MVC 程序1.1 什么是 MVC 2. Spring MVC 概述2.1 Spring MVC 的作用: 3. 运行配置第一个 Spring MVC 程序3.1 第一步:创建Maven模块3.2 第二步:添加 web 支持3.3 第三步:配置 w

驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法

在连接数据库的时候出现了下面图面中的错误,尝试集中方法后终于解决了这个问题。 1.修改驱动程序版本 出现这种错误可能是因为你的驱动程序版本不兼容,我们可以尝试修改版本解决。而我们的驱动程序往往是以依赖的形式导入,因此可以在maven仓库查找你的数据库对应的驱动程序,选择一个数据库能够兼容的版本导入。 maven仓库官网:https://mvnrepository.com/ 2.在 VM opt

测试辅助工具(抓包工具)的使用1 之初识抓包工具(fiddler)

1.什么是抓包? 说明:客户端向服务器发送请求以及服务器响应客户端的请求,都是以数据包来传递的。 抓包(packet capture):通过工具拦截客户端与服务器交互的数据包。 抓包后可以修改数据包的内容  2.为什么要抓包? 确定bug是前端研发人员的还是后端研发人员的 3.如何抓包? 1)使用抓包工具Fiddler 2)Fiddler介绍: Fiddl

第十六章 非阻塞I/O

第十六章、非阻塞式I/O 什么是阻塞socket和非阻塞socket?两者的具体区别是什么?     读操作         对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的

UDP编程初识

复习: TCP     每个TCP套接字都有一个发送区,我们可以使用SO_SNDBUF来更改缓冲区的大小,当进程调用write时,内核从该应用进程的缓冲区中复制所有数据到套接字的缓冲区。如果该套接字的发送缓冲区容不下该应用进程的所有数据(或是应用进程的缓冲区大于套接字的发送缓冲区,或是套接字的发送缓冲区已有其他数据),该应用进程将被投入睡眠(这里的套接字是阻塞的),内核将不从write系统

第十六章(二) 套接字初识

 数据传输:  尽管可以通过 read 和 write 交换数据,但这就是这两个函数所能作的一切。但是如果想要指定选项,从多个客户端接收数据包,或者发送带外数据,就需要使用6个为数据传递而设计的套接字函数。  三个传送数据的套接字函数: <span style="color:#000000;">ssize_t send(int sockfd, void *buf, size_t n

Libevent源码分析之event结构体初识

I/O框架库以库函数的形式,封装了较为底层的系统调用,给应用程序提供了一组更为便捷的接口 各种I/O框架库的实现原理基本相似,要么以Reactor模式实现,要么以Proactor模式实现,要么同时用这两种模式。 拿基于Reactor模式的I/O框架库来说,包含以下几个组件: 1、句柄     I/O框架库要处理的对象,即I/O事件、信号和定时事件,统一称为事件源。一个事件源通常和