专栏首页Pou光明Linux C Socket Api详解

Linux C Socket Api详解

文章主要梳理于《UNIX 环境高级编程第二版》 第十六章 网络IPC: 套接字

以前都只是在网上搜的能用的例子,对一些参数不是很清楚,这次汇总。而且网络通信还是很常用的通信手段。

UNIX 环境高级编程对Socket通信的描述是套接字网络IPC(进程间通信),可以用于计算机间通信也可用于计算机内通信,管道、消息队列、信号量以及共享内存等都是属于计算机内通信的情况。

一、 套接字Api详细介绍

1. 套接字描述符

首先会先到的是文件描述符,对Linux一切皆文件的哲学又多懂了一点儿点儿。

套接字是通信端点的抽象。与应用程序使用文件描述符一样,访问套接字需要使用套接字描述符。套接字描述符在UNIX系统是用文件描述符实现的。

#include  <sys/socket.h>
int  socket (int domain, int type, int protocal);
返回值:成功返回文件(套接字)描述符,出错返回-1

参数domain(域)确定通信的特性,包括地址格式。各个域都有自己的格式表示地址,表示各个域的常数都以AF_开头,意指地址族(address family).

参数type确定套接字的类型,进一步确定通信特征。下图给出了一些类型,但在实现中可以自由增加对其他类型的支持。

参数protocol通常是0,表示按给定的域和套接字类型选择默认的协议。当对同一域和套接字类型支持多个协议时,可以使用proticol参数选择一个特定协议。在A_FINET通信域中套接字类型SOCK_STREAM的默认协议是TCP(传输控制协议);A_FINET通信域中套接字类型SOCK_DGRAM的默认协议是UDP(用户数据报协议)。

字节流(SOCK_STREAM)要求在交换数据之前,在本地套接字和远程套接字之间建

立一个逻辑联系。

Tcp:没有报文界限,提供的是字节流服务。之前写过Qt传输图片的拆包与解包,原因就是如此吧。

调用socket与调用open类型,均可获得用于输入、输出的文件描述符。不用的时候记得close关闭。

2. 寻址

如何确定一个目标通信进程?

进程的标识有两个部分:计算机的网络地址可以确定网络上与之想要通信的计算机

服务可以确定计算机上的特定进程。

2.1 字节序

在同一台计算机上进程间通信时,一般无需考虑字节序。

TCP/IP协议栈使用大端字节序。有关字节序大家可自行百度。

Linux系统是小端字节序。

2.2 地址格式

地址确定了特定通信域中的套接字端点,地址格式与特定的通信域相关。为使不同格式的地址能够被传入到套接字函数,地址被强转换成通用的地址结构sockaddr表示。

Linux中,sockaddr_in定义如下:

struct sockaddr_in {
sa_family_t    sin_family;
in_port_t      sin_port;
struct  in_addr   sin_addr;
unsigned char    sin_zero[8];
};

其中成员sin_zero为填充字段,必须全部置0. 所以在网上搜到的例子有使用bzero.

我目前使用的ubuntu定义如下:

/* 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.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
         __SOCKADDR_COMMON_SIZE -
         sizeof (in_port_t) -
         sizeof (struct in_addr)];
  };

还有很多关于地址查询的函数,这里就不一一列举了。

3. 将套接字与地址绑定

使用bind函数将地址绑定到一个套接字上。

#include  <sys/socket.h>
int bind(int  sockfd, const struct sockaddr * addr, socklen_t  len);
返回值:成功返回0,出错返回-1

参数socklen_t使用sizeof来计算就好了。

对于使用地址的一些限制:

端口号不能小于1024,除非该进程具有相应的特权(即为超级用户)。可见规则总是因人而异,计算机也是如此~

对于因特网域,如果指定IP地址为ADDR_ANY,套接字端点可以被绑定到所有的系统网络接口。

注意:linux的man命令可以查看api的详细说明,而且还有例子,也挺不错的。

4. 建立连接

1> connect

如果处理的是面向连接的网络服务(SOCK_STREAM或SOCK_SEQPACKET),在开始交换数据前,需要在请求服务的进程套接字(客户端)和提供服务的进程套接字(服务器)之间建立一个连接。使用connect.

#include  <sys/socket.h>
int connect(int  sockfd, const struct sockaddr  *addr,  socklen_t  len);
返回值:成功返回0,出错返回-1

诶,这个参数好熟悉呀,和bind函数的参数一模一样呀~

当client连接server时,由于一些原因,连接可能会失败。可以使用指数补偿的算法解决,了解一下即可。

2> listen

server调用listen来宣告可以接受连接请求:

#include  <sys/socket.h>
Int listen(int  sockfd, int  backlog);
返回值:成功返回0,出错返回-1

参数backlog提供了一个提示,用于表示该进程所要入队的连接请求数量。其值由系统决定,但上限由<sys/socket.h>中SOMAXCONN指定。

一旦队列满,系统会拒绝多余的连接请求。

3> accept

一旦服务器调用了listen,套接字就能接收连接请求。使用函数accept获得连接请求并建立连接。

#include  <sys/socket.h>
Int accept(int sockfd,  struct sockaddr *restrict  addr, socklen_t *restrict  len);
返回值:成功返回文件(套接字)描述符,出错返回-1

函数accept所返回的文件描述符是套接字描述符,该描述符连接到调用connect的客户端。这个新的套接字描述符和原始套接字(sockfd)具有相同的套接字类型和地址族。传给accept的原始套接字没有关联到这个连接,而是继续保持可用状态并接受其他连接请求。

如果不关心客户端标识,可以将addr和len设置为NULL,否则addr存放的是连接的客户端的地址。

如果没有连接请求等待处理,accept会阻塞直到有请求到来。另外server可以使用poll或select来等待一个请求的到来。

5. 数据传输

既然将套接字端点表示为文件描述符,那么只要建立连接,就可以使用read和write来通过套接字通信。read和write函数我几乎不用,了解一下即可。

1> send

#include  <sys/socket.h>
Int send(int sockfd,  const void *buf,  size_t  nbytes,  int  flags);
返回值:成功返回发送的字节数,出错返回-1

注意:如果send成功返回,并不一定并表示连接的另一端的进程接收数据。可以保证的是数据已经无误的发送到网络上。

标志我一直用的是0

2> recv

#include  <sys/socket.h>
int recv(int sockfd,  const void *buf,  size_t  nbytes,  int  flags);
返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,      出错返回-1

仍然一直是0

如果想定位发送者,可以使用recvfrom来得到数据发送者的源地址。

3> recvfrom

#include  <sys/socket.h>
int recv(int sockfd,  void *restrict buf, size_t len, int flag, 
struct sockaddr *restrict  addr, 
socklen_t *restrict  len);
返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,      出错返回-1

因为可以获得发送者的地址,recvfrom通常用于无连接套接字。否则,recvfrom等同于recv。

二、 小结

这里面再提一个带外数据,感兴趣的同志可以自行百度。

之前写过一个server和client的例子,连接如下,可对应本文做对比阅读。

Linux Socket Server 与 Client 例子

个人觉得这只是套接字的入门,如果一个服务器要连接多个客户端呢?以后有机会和大家一起分享下select的套接字用法。

思考:毕业后的学习与在学校的学习有什么区别呢 ?

本文分享自微信公众号 - Pou光明(pou0230),作者:PouG

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • yasio-3.33.0发布了

    距离上一个版本v3.31.3发布,已经过去3个多月,对yasio的维护并没有停歇,v3.33.0主要更新内容如下:

    simdsoft
  • C# Socket编程 笔记,Socket 详解,入门简单

    文章按照 Socket 的 创建、连接、传输数据、释放资源的过程来写。给出方法、参数的详细信息。

    痴者工良
  • Linux入门、深入

    学习步骤如下:              1、Linux 基础             安装Linux操作系统              Linux文件系...

    猿人谷
  • Java16的新特性

    上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 16 Release Notes,这里举几个例子。

    codecraft
  • Java16的新特性

    上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 16 Release Notes,这里举几个例子。

    codecraft
  • Socket 编程

    最近在录一套关于 Web 页面获取 MAC 地址的视频,Web 页面要获取 MAC 地址是以前项目中的真实案例,其中的解决方法也换了几波。最终的...

    码农UP2U
  • linux网络编程之socket(一):socket概述和字节序、地址转换函数

    一、什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口。 socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程...

    s1mba
  • 开发成长之路(13)-- Linux网络服务端编程(通识篇)

    引用一句经典的话:“UNIX下一切皆文件”。 文件是一种抽象机制,它提供了一种方式用来存储信息以及在后面进行读取。

    看、未来
  • linux网络编程之socket(十五):UNIX域套接字编程和socketpair 函数

    一、UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX...

    s1mba
  • 你心中最高大上最牛X的技术到底是什么

    **高以下为基,贵以贱为本 互联网技术的核心根基就是TCP/IP,TCP/IP的实现依赖于Linux socket API【我们的项目大部分运行在上面】 没有...

    北溟有鱼QAQ
  • linux中crw brw lrw等等文件属性是什么

    所有的文件其实都是一串字符流,不过当用合适的解析方法,可以得到有效信息,人们为了方便对文件进行操作,便按照文件的解析方法的不同,给了文件不同的种类,并用下边的方...

    砸漏
  • 嵌入式驱动工程师学习路线【建议收藏】

    网上看了很多的嵌入式学习路线,有的比较片面,有的为了博人眼球东拼西凑,几乎把整个行业用得着用不着的技术都写上去了,没有侧重点,简直是劝退指南,还有的纯粹是打广告...

    Jasonangel
  • linux下用户程序同内核通信详解(netlink机制)

    linux下用户程序同内核通信的方式一般有ioctl, proc文件系统,剩下一个就是Netlink套接字了。 这里先介绍下netlink。

    砸漏
  • Python C API 使用详解(二)

    介绍Python C API中的列表、元组、字典的使用,详细的进行了API中方法的介绍。

    py3study
  • 开源Mono框架将C#编程带到iPhone、Android和Wii

    Mono,作为.NET运行库的开源实现,正在将微软的技术带到未曾预料到的地方,包括iPhone,Android和Wii。 根据Novell公司的首席Mono...

    张善友
  • C++ 如何进阶?如何准备 C++ 面试?

    在大多数开发或者准开发人员的认识中,C/C++ 是一门非常难的编程语言,很多人知道它的强大,但因为认为“难”造成的恐惧让很多人放弃。

    范蠡
  • WebSocket详解(六):刨根问底WebSocket与Socket的关系1、前言2、系列文章3、更多资料4、技术对比5、OSI 模型与 TCP/IP6、WebSocket 与 TCP7、再来八卦一

    对于很多初次接触Web端即时通讯技术的人来说,WebSocket是个很新的概念,但无疑它是当前Web端即时通讯技术中最热门的关键词。随便点开一篇文章,只要说打算...

    JackJiang
  • 一个简单的游戏服务器框架_游戏开发

    最近一段时间不是很忙,就写了一个自己的游戏服务器框架雏形,很多地方还不够完善,但是基本上也算是能够跑起来了。我先从上层结构说起,一直到实现细节吧,想起什么就写...

    李海彬
  • 知识点查缺补漏贴03:单机最大进程数,线程数和Socket连接数

      参加Unix/Linux相关高级研发职位时,是否经常会被文档,单机允许最大进程数、线程数和Socket连接数,而你却感到束手无措呢?本文给你一个最为详细的答...

    数据饕餮

扫码关注云+社区

领取腾讯云代金券