TCP 网络编程API - socket()

目录​​​​​​​

 

socket()

socket()函数介绍

应用层函数socket() 和内核函数之间的关系

示例


socket()

网络程序设计中的套接字系统调用 socket()函数用来获得文件描述符。

socket()函数介绍

# include <sys/types.h>
# include <sys/socket.h>
int socket(int domain, int type, int protocol);

这个函数建立一个协议族为 domain 、协议类型为 type 、协议编号为 protocol 的套接字文件描述符。如果函数调用成功,会返回一个表示这个套接字的文件描述符,失败的时候返回-1。

函数 socket()的第一个参数 domain 用于设置网络通信的域,函数 socket()根据这个参数选择通信协议的族。通信协议族在文件 sys/socket.h 中定义,以太网中应该使用PF_ INET 这个域。在程序设计的时候会发现有的代码使用了 AF_INET 这个值,在头文件中 AF_INET 和 PF_INET 的值是一致的。

domain 的值及含义

名称含义
PF_UNIX , PF_LOCAL本地通信
PF_INET IPv4 Internet 协议
PF_INET6IPv6 Internet 协议
PF_IPXIPX - Novel 协议
PF_NETLINK 内核用户界面设备
PF_X25 ITU - TX.25/ ISO -8208协议
PF_AX25Amateur radio AX.25协议
PF_ATMPVC 原始 ATM PVC 访问
PF_APPLETALK Appletalk 
PF_PACKET 底层包访问

函数 socket()的参数 type 用于设置套接字通信的类型,主要有 SOCK_STREAM(流式套接字)、 SOCK_DGRAM (数据包套接字)等。

 type 的值及含义

名称含义
SOCK_STREAM  TCP 连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
SOCK_DGRAM支持 UDP 连接(无连接状态的消息)
SOCK_SEQPACKET 序列化包,提供一个序列化的、可靠的、双向的基于连接的数据传输通道,数据长度定长。每次调用读系统调用时数据需要将全部数据读出
SOCK_RAW  RAW 类型,提供原始网络协议访问
SOCK_RDM 提供可靠的数据报文,不过数据可能会有乱序
SOCK_PACKET 这是一个专用类型,不能在通用程序中使用

并不是所有的协议族都实现了这些协议类型,例如, AF_INET 协议族就没有实现 SOCK_SEQPACKET 协议类型。

函数 socket()的第3个参数 protocol 用于指定某个协议的特定类型,即 type 类型中的某个类型。通常某个协议中只有一种特定类型,这样 protocol 参数仅能设置为0;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。

        类型为 SOCK_STREAM 的套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用 connect() 函数进行。一旦连接,可以使用 read() 或者 write()函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收,当数据在一段时间内仍然没有接收完毕,可以认为这个连接已经死掉。

        SOCK_DGRAM 和 SOCK_RAW 这两种套接字可以使用函数 sendto()来发送数据,使用 recvfrom()函数接收数据, recvfrom()接收来自指定 IP 地址的发送方的数据。

        SOCK_PACKET 是一种专用的数据包,它直接从设备驱动接收数据。

函数 socket()并不总是执行成功,有可能会出现错误,错误的产生有多种原因,可以通过 errno 获得,通常情况下造成函数 socket() 失败的原因是输入的参数错误造成的,例如某个协议不存在等,这时需要详细检查函数的输入参数。由于函数的调用不一定成功,在进行程序设计的时候,一定要检查返回值。

errno 的值及含义

 使用socket() 函数时需要设置上述3个参数,如将socket()函数的第一个参数设置为AF_INET,第二个参数设置为SOCK_STREAM,第三个参数设置为0,建立一个IPV4的流失套接字。

int sock = socket(AF_INET, SOCK_STREAM, 0);

应用层函数socket() 和内核函数之间的关系

用户设置套接字的参数后,函数要能够起作用,需要与内核空间的相关系统调用交互。应用层socket() 函数与系统调用sys_socket的关系见下:

图中用户调用函数 sock = socket(AF_INET, SOCK_STREAM , 0),这个函数会调用系统调用函数 sys_socket(AF_ INET , SOCK_STREAM ,0)(在文件 net / socket.c 中)。系统调用函数 sys_socket()分为两部分,一部分生成内核 socket 结构(注意与应用层的 socket()函数是不同的),另一部分与文件描述符绑定,将绑定的文件描述符值传给应用层。内核 sock 结构
如下(在文件 linux/net.h 中):

struct socket
{
    socket_state           state;         /*socket 状态(例如 SS_CONNECTED 等)*/
    unsigned long          flags;         /*socket 标志(SOCK_ASYNC_NOSPACE 等)*/
    const struct proto_ops *ops;          /*协议特定的 socket 操作*/
    struct fasync_struct   *fasync_list ; /*异步唤醒列表*/
    struct file            *file;         /*文件指针*/
    struct sock            *sk ;          /*内部网络协议结构*/
    wait_queue_headt       wait ;         /*多用户时的等待队列*/
    short                  type ;         /* socket 类型( soCK _ STREAM 等)*/
};

内核函数 sock_create()根据用户的 domain 指定的协议族,创建一个内核 socket 结构绑定到当前的进程上,其中的 type 与用户空间用户的设置值是相同的。
sock_map_fd()函数将 socket 结构与文件描述符列表中的某个文件描述符绑定,之后的操作可以查找文件描述符列表来对应内核 socket 结构。

示例

#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == socket_fd)
    {
    	printf("create socket fail\n");
    	return -1;
    }

    ...

    close(socket_fd);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值