套接字编程1 ------ 涉及的主要API函数 - 2

本文介绍了网络编程中的关键概念,包括字节顺序转换、IP地址转换、套接字属性修改及多路复用技术。通过这些基础知识的学习,读者可以更好地理解网络编程的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络字节顺序转换函数

      不同机器存储数据的字节顺序不同,有大端模式(big-endian)和小端模式(little-endian)。TCP/IP协议规定在网络上传输数据必须采用大端模式(也即网络字节顺序)。Linux系统为大小端模式的转换提供了4个函数。其原型分别如下:

#include <netinet/in.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);

      htonl中的“h”代表host(主机),“n”代表net(网络),“l”代表long型,同理,“s”代表short型。


IP地址转换函数

      通常人们习惯于使用字符串形式的网络地址,比如“198.22.104.3”。然而在网络上传输数据时,需要使用的是二进制形式,且为网络字节顺序的IP地址。Linux系统为网络地址的格式转换提供了一些列函数。原型如下:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_network(const char *cp);
char * inet_ntoa(struct in_addr in);

  • inet_aton()将参数cp所指向的字符串形式的IP地址转换为二进制的网络字节顺序的IP地址,转换后的结果存于参数inp所指向的空间中。
  • inet_ntoa()将值为in的网络字节顺序形式的二进制IP地址转换成以“.”分隔的字符串形式,执行成功返回结果字符串的指针。
  • inet_network()将参数cp所指向的字符串形式的网络地址转换为主机字节顺序形式的二进制IP地址。

修改套接字属性
      创建套接字后,在使用时可能还需要修改其属性。使用函数getsockopt可以获取套接字的属性,使用setsockopt可以设置套接字的属性。原型如下:
#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t *optlen);

  • 参数s为一个套接字。
  • 参数level是进行套接字选项操作的层次。一般取SOL_SOCKET来进行与特定协议无关的操作。
  • 参数optname是套接字选项的名称。
  • 参数optval用来存放获得的套接字选项的值,或者是待设置的套接字选项的值。
  • 参数optlen是该选项的长度。
      通用套接字SOL_SOCKET的选项。

      SO_KEEPALIVE:如果没有设置此选项,那么及时TCP连接已经很长时间没有数据传输时,系统也不会检测这个连接是否还有效。对于服务器进程,如果某一个客户端非正常断开连接,则服务器进程将一直被阻塞等待。因此服务器端程序需要设置这个选项,如果某个客户端一段时间内没有反应则关闭该连接。

      SOL_SOCKET还有若干其他选项,此处从略。


多路复用

      在客户端/服务器模型中,服务器需要同时处理多个客户端的连接请求,此时就需要使用多路复用。实现多路复用最简单的方法是采用非阻塞方式套接字,服务器端不断地查询各个套接字的状态,如果有数据到达则读出数据,如果没有数据则查看下一个套接字。这种方法简单,但是,在轮询过程中浪费了大量的CPU实际,效率非常低下。

      正确的做法是,服务器进程并不主动询问套接字的状态,而是向系统登记希望监视的套接字,然后阻塞。当套接字上有事件发生时(如有数据到达),系统通知服务器进程告知哪个套接字上发生了什么事件,服务器进程查询对应套接字并进行处理。套接字上没有事件发生时,服务器进程不会去查询套接字的状态,不会浪费CPU时间,提高了效率。使用select()函数可以实现这样的多路复用。该函数原型:

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

  • 参数n是需要监视的文件描述符数,要监视的文件描述符值为0~n-1
  • 参数readfds指定需要监视的可读文件描述符集合。当此集合中任一描述符上有数据到达时,系统将通知调用select函数的程序
  • 参数writefds指定需要监视的可写文件描述符集合,当此集合中任一描述符可以发送数据时,调用进程将受到通知
  • 参数exceptfds指定需要监视的异常文件描述符集合,当集合中任一描述符发生异常时,调用进程将受到通知
  • 参数timeout指定了阻塞的时间,如果在此时间内监视的文件描述符上没任何事件发生,则函数select()将返回0;如果将timeout设置为NULL,则select()函数将一直阻塞;如果将timeout设为0,则此时相当于非阻塞方式,函数select()查询完文件描述符集合的状态后立即返回

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值