简体   繁体   English

c socket()函数中类型和协议有什么区别?

[英]What is the difference between type and protocol in c socket() function?

I'm reading and trying to get an idea of C , and I tried to program a Java chat with UDP and TCP a couple of years back, and as much as I pulled it off... I could not do it. 我正在阅读并尝试了解C ,并且几年前我尝试使用UDPTCP UDP Java chat程序,并且尽可能地将其删除...我无法做到。 I want to program sockets and I'm reading tons of documentation, but there is always a part that is unclear, every kicking documentation has a flaw. 我想编写套接字并且我正在阅读大量的文档,但总有一部分不清楚,每个踢文档都有一个缺陷。 For example, there is one about 例如,有一个关于

int socket(int domain, int type, int protocol);

The domain I will use is clearly AF_INET , and if I want a TCP Socket I think type should be SOCK_STREAM , but what is protocol? 我将使用的域显然是AF_INET ,如果我想要TCP套接字,我认为类型应该是SOCK_STREAM ,但什么是协议? Documentation says it should be 0... why??? 文档说它应该是0 ...为什么??? what is it? 它是什么?

From the man page for socket: 从socket的手册页:

The protocol specifies a particular protocol to be used with the socket. 该协议指定了与套接字一起使用的特定协议。 Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. 通常,只有一个协议支持给定协议族中的特定套接字类型,在这种情况下协议可以指定为0.但是,可能存在许多协议,在这种情况下,必须在此指定特定协议方式。 The protocol number to use is specific to the “communication domain” in which communication is to take place; 要使用的协议号特定于进行通信的“通信域”; see protocols(5). 见协议(5)。 See getprotoent(3) on how to map protocol name strings to protocol numbers. 有关如何将协议名称字符串映射到协议号,请参阅getprotoent(3)。

According to the man page for protocols: 根据协议的手册页:

This file is a plain ASCII file, describing the various DARPA internet protocols that are available from the TCP/IP subsystem. 此文件是纯ASCII文件,描述了TCP / IP子系统中可用的各种DARPA Internet协议。 It should be consulted instead of using the numbers in the ARPA include files, or, even worse, just guessing them. 应该参考它而不是使用ARPA包含文件中的数字,或者更糟糕的是,只是猜测它们。 These numbers will occur in the protocol field of any IP header. 这些数字将出现在任何IP标头的协议字段中。

Each line is of the following format: 每行的格式如下:

protocol number aliases ... 协议号别名...

... ...

/etc/protocols The protocols definition file. / etc / protocols协议定义文件。

And in the /etc/protocols file on my linux box: 在我的linux盒子上的/ etc / protocols文件中:

ip      0       IP              # internet protocol, pseudo protocol number
hopopt  0       HOPOPT          # hop-by-hop options for ipv6
icmp    1       ICMP            # internet control message protocol
igmp    2       IGMP            # internet group management protocol
ggp     3       GGP             # gateway-gateway protocol
ipencap 4       IP-ENCAP        # IP encapsulated in IP (officially ``IP'')
st      5       ST              # ST datagram mode
tcp     6       TCP             # transmission control protocol
cbt     7       CBT             # CBT, Tony Ballardie <A.Ballardie@cs.ucl.ac.uk>
egp     8       EGP             # exterior gateway protocol
igp     9       IGP             # any private interior gateway (Cisco: for IGRP)
bbn-rcc 10      BBN-RCC-MON     # BBN RCC Monitoring
...

And according to the man page for getprotocol: 并根据getprotocol的手册页:

The getprotobyname() function returns a protoent structure for the entry from the database that matches the protocol name name. getprotobyname()函数从数据库返回与协议名称名称匹配的条目的protoent结构。 A connection is opened to the database if necessary. 如有必要,将打开与数据库的连接。

... ...

The protoent structure is defined in as follows: protoent结构定义如下:

 struct protoent { char *p_name; /* official protocol name */ char **p_aliases; /* alias list */ int p_proto; /* protocol number */ } 

So if you pass "ip" to getprotobyname() it would return 0 which is the number you are using anyway. 因此,如果您将“ip”传递给getprotobyname(),它将返回0,这是您正在使用的数字。 But using 0 directly is always safe even if you don't know the name of the protocol. 但即使您不知道协议的名称,直接使用0也总是安全的。

There may be different protocols to support a particular socket type, so that's why you also can specify the protocol in socket(2) . 可能有不同的协议来支持特定的套接字类型,这就是为什么你也可以在socket(2)指定protocol的原因。

From the manpage (emphasis mine): 从联机帮助页(强调我的):

The protocol specifies a particular protocol to be used with the socket. 该协议指定了与套接字一起使用的特定协议。 Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. 通常,只有一个协议支持给定协议族中的特定套接字类型,在这种情况下协议可以指定为0. 但是,可能存在许多协议,在这种情况下,必须在此指定特定协议方式。

So it is not mandatory to specify the protocol as 0 . 因此,它不是强制性的指定协议为0 Actually 0 means that the standard library will figure out the correct protocol for you. 实际上0意味着标准库将为您找出正确的协议。 But you could specify it as explicitly and it is perfectly valid to do so. 但是你可以明确地指定它,这样做是完全有效的。

On Linux, you can see the available protocols by doing: 在Linux上,您可以通过以下操作查看可用的协议:

$ cat /etc/protocols
# Internet (IP) protocols
#
# Updated from http://www.iana.org/assignments/protocol-numbers and other
# sources.
# New protocols will be added on request if they have been officially
# assigned by IANA and are not historical.
# If you need a huge list of used numbers please install the nmap package.

ip  0   IP      # internet protocol, pseudo protocol number
hopopt  0   HOPOPT      # IPv6 Hop-by-Hop Option [RFC1883]
icmp    1   ICMP        # internet control message protocol
igmp    2   IGMP        # Internet Group Management
ggp 3   GGP     # gateway-gateway protocol
ipencap 4   IP-ENCAP    # IP encapsulated in IP (officially ``IP'')
st  5   ST      # ST datagram mode

The last protocol parameter of socket() can be used with raw packets. socket()的最后一个协议参数可以与raw包一起使用。 I will try to explain it practically. 我会尝试解释它。

If you are using raw sockets to get packets from TCP stack, you can control the amount of packet data you want to send/receive with this parameter. 如果使用原始套接字从TCP堆栈获取数据包,则可以使用此参数控制要发送/接收的数据包数据量。

socket (AF_INET, SOCK_RAW, IPPROTO_TCP);

Above call will give you a raw packet in which kernel will take care of the packet up to IP header. 上面的调用将为您提供一个原始数据包,其中内核将处理数据包到IP头。 You will have to manually fill in the rest of the packet when sending it or when you will read the packet, kernel will provide the contents of TCP header as well with the data. 您必须在发送数据包时手动填写其余数据包,或者当您读取数据包时,内核将提供TCP标头的内容以及数据。

On the other hand: 另一方面:

socket (AF_INET, SOCK_RAW, IPPROTO_RAW);

Using IPPROTO_RAW , you can control the packet from IP layer upwards. 使用IPPROTO_RAW ,您可以从IP层向上控制数据包。 ie kernel will provide you services up to ethernet header, rest of the packet is in your control. 即内核将为您提供以太网头的服务,其余的数据包在您的控制之下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM