最近开始研究使用Socket API来网络编程,想着把自己的感想、感悟写下来。我发现在编程之外还有不少概念性的东西要学习。我觉得应该有以下几点吧:
1.得了解下计算机网络的基本概念,如OSI的7层模型,TCP/IP协议,地址端口等。TCP/IP协议相关的知识推荐看国外的教材;
2.了解计算机网络中两个结点之间通信的基本过程,以及IP地址、端口的基本概念。比如应用层的数据如何通过传输层协议包装,再通过IP层协议包装等等;
3.使用Socket API编程的基本流程和技术思路;
在使用Socket API编程时,需要重点先了解几个API,包括:socket、accept()、bind()、connect()等。关于这几个函数的解释,我觉得国外的英文解释是最准确的了,因此我想着把英文翻译出来,希望对学习Socket网络编程的朋友有帮助。
本篇翻译的socket()函数,我参考的国外网站是:
朋友们可以自由转载我对英文的中文翻译,但是对于“作者注:”的描述,转载时请注明出处和作者,否则视为侵权。
下面是翻译的正文,由于水平有限,有些翻译的不好,有些未能翻译出,恳请读者指出与见谅。
NAME
socket - create an endpoint for communication
socket,为通信创建一个终端点;
SYNOPSIS
include <sys/socket.h>
int socket(int domain, int type, int protocol);
socket函数声明是在头文件<sys/socket.h>中。函数包含三个参数:domain,type,protocol;
DESCRIPTION
The socket() function creates an unbound socket in a communications domain, and returns a file descriptor that can be used in later function calls that operate on sockets.
socket()函数在一个通信域创建了一个未被绑定的套接字,此函数返回一个文件描述符。这个文件描述符会被其他的函数调用。这些函数都要在套接字上做一些操作。
作者注:
1.socket()函数会创建一个socket文件,并且返回了一个文件描述符。在Linux中,一切都是文件。既然是文件,肯定要有一个东东来标记它,而且还是唯一的标记。函数返回的文件描述符就是这样一个标记。
2.返回的文件描述符是一个int型数据,用来标记创建的socket;
3.由于创建的socket是一个文件,所以socket就可以被用来读、写等I/O文件操作。谁来执行这些操作呢?就是所翻译的“其他的函数”,比如bind()等函数。这些函数的参数往往第一个就是socket()函数返回的文件描述符,也就是引用文件描述符来使用socket。至于socket这个东东如何从形象的角度来理解,作者想了一个比方,附在文末。
The function takes the following arguments:
socket()函数的参数如下:
domain
Specifies the communications domain in which a socket is to be created.
参数domain:指定了一个socket在哪个通信域被创建。
作者注:
我觉得其实就是指定了这个socket将来要使用的是IPV4地址,还是IPV6地址等。
type
Specifies the type of socket to be created.
参数type:指定了被创建的socket的类型;
protocol
Specifies a particular protocol to be used with the socket. Specifying a protocol of 0 causes socket() to use an unspecified default protocol appropriate for the requested socket type.
参数protocol:指定了套接字需要用到的某个特殊的协议。如果此参数为0,则会导致socket()函数使用一个未指定的默认的协议,默认协议适用于请求的套接字类型。
作者注:
如果protocol参数为0的话,则参数type是什么类型,那么参数protocol就是此类型默认使用的协议。比如type是SOCK_STREAM类型,那么protocol默认就是TCP协议。
The domain argument specifies the address family used in the communications domain. The address families supported by the system are implementation-dependent.
参数domain指定了在通信域里使用的地址族。此地址族是依赖于所使用的系统实现。
作者注:
比如有的系统不支持IPV6,就算domain参数指定了是IPV6,系统也用不了。
The <sys/socket.h> header defines at least the following values for the domain argument:
关于domain参数的值,<sys/socket.h>头文件定义了至少如下几个值:
AF_UNIX
File system pathnames.
AF_UNIX值:是文件系统路径名;
AF_INET
Internet address.
AF_INET值:是网络地址。
作者注:
AF_INET表示socket会用IPV4地址来通信。IPV4地址采用32位。
The type argument specifies the socket type, which determines the semantics of communication over the socket. The socket types supported by the system are implementation-dependent. Possible socket types include:
参数type指定了套接字的类型,套接字的类型决定了在套接字上进行通信时的通信语义。可能的套接字类型包括:
SOCK_STREAM
Provides sequenced, reliable, bidirectional, connection-mode byte streams, and may provide a transmission mechanism for out-of-band data.
SOCK_STREAM:此种类型提供了有序的,可依赖的,双向的,字节流连接模式,而且可能为out-of-band数据提供一种传输机制。
作者注:
1. SOCK_STREAM:应该就是使用的是TCP协议。TCP协议就是一种面向连接的可靠的协议,保证传输数据不会丢失。只要有数据丢失,则通信双方会继续传输丢失的数据,所以TCP协议效率上可能会打点折扣。
2. out-of-band我不知该如何翻译。可能是说,SOCK_STREAM提供的传输机制可以保证丢失的数据再找回来吧。
SOCK_DGRAM
Provides datagrams, which are connectionless-mode, unreliable messages of fixed maximum length.
SOCK_DGRAM:此种类型提供了数据报文,这种报文是面向未连接的,不可靠的信息,且是固定的最大长度。
作者注:
比如使用UDP协议就是一种面向未连接的方式,通信双方传信时丢了数据也不管,所以传输效率上比TCP协议要高一些。
SOCK_SEQPACKET
Provides sequenced, reliable, bidirectional, connection-mode transmission path for records. A record can be sent using one or more output operations and received using one or more input operations, but a single operation never transfers part of more than one record. Record boundaries are visible to the receiver via the MSG_EOR flag.
SOCK_SEQPACKET:此种类型为记录提供了有序的,可靠的,双向的,面向连接的传输路径。一个记录可以用一个或多个输出操作将其发出去,也可以使用一个或多个输入操作将其接收,但是一个单独的操作永远不会传输part of more than one record.记录的边界通过“MSG_EOR”标记对接受者而言是可见的。
If the protocol argument is non-zero, it must specify a protocol that is supported by the address family. The protocols supported by the system are implementation-dependent.
如果protocol参数是非0的数,那么一定要为此参数指定一个地址族支持的协议。系统支持的协议是依赖于该系统的。
作者注:
“type”参数与“protocol”参数不是随便组合的。比如,“type”是SOCK_STREAM时,“protocol”一定得是TCP协议。
The process may need to have appropriate privileges to use the socket() function or to create some sockets.
进程也许需要合适的授权来使用socket()函数,或者进程需要创建一些套接字。
RETURN VALUE
Upon successful completion, socket() returns a nonnegative integer, the socket file descriptor. Otherwise a value of -1 is returned and errno is set to indicate the error.
ERRORS
一旦函数成功执行,socket()会返回一个正数,也就是套接字文件描述符。否则,就会返回-1,而且会有errno会被用来说明发生了什么错误。
The socket() function will fail if:
socket()函数会由于以下原因执行失败:
[EAFNOSUPPORT]
The implementation does not support the specified address family.
实现不支持指定的协议族。
[EMFILE]
No more file descriptors are available for this process.
此进程没有更多可用的文件描述符。
[ENFILE]
No more file descriptors are available for the system.
系统没有更多可用的文件描述符。
[EPROTONOSUPPORT]
The protocol is not supported by the address family, or the protocol is not supported by the implementation.
地址族不支持指定的协议,或者协议不被实现所支持;
[EPROTOTYPE]
The socket type is not supported by the protocol.
套接字类型不被协议所支持。
The socket() function may fail if:
socket()函数会由于以下原因可能会失败:
[EACCES]
The process does not have appropriate privileges.
进程没有相应的权限。
[ENOBUFS]
Insufficient resources were available in the system to perform the operation.
系统中没有足够的资源来执行操作。
[ENOMEM]
Insufficient memory was available to fulfill the request.
没有足够的内存来满足要求。
[ENOSR]
There were insufficient STREAMS resources available for the operation to complete.
操作要完成,但是没有足够的流资源。
APPLICATION USAGE
The documentation for specific address families specify which protocols each address family supports. The documentation for specific protocols specify which socket types each protocol supports.
具体的地址族的文档指定了每个地址族支持哪些协议。具体协议的文档指定了每一个协议支持哪些套接字类型。
The application can determine if an address family is supported by trying to create a socket with domain set to the protocol in question.
不知如何翻译。
作者注:
作者一直在思考该怎么从形象的角度来理解socket这个概念,想了几天,遂想出一个比喻,岁不太贴切,但也可帮助理解。
从英文单词来看,此socket单词的意思是“插座”,也就是老外拿插座这个日常用品来描述socket编程。我们都知道的,插座提供了几个插孔为家用电器提供电力,家用电器的电源适配器插在插座上,插座再通过自己的电源线从总电源处获取电力。那么用来类别socket编程,就好像将通信的电脑插在一个socket上,电脑通过这个socket来获取网络上的数据,或者把数据发到网络上。比如我的电脑要跟小张电脑通信,编程时,将一个socket绑在我的电脑上,socket从小张电脑获取数据,再给到我,就好像插座从总电源获取电力,再给我的电脑供电。而且,我的电脑还能把数据发给socket,由socket把数据发给小张的电脑,就好像我的电脑把自己的电力给了插座,插座又给了总电源,虽然这个是不可能的啦!
这样一比喻的话,就比较好理解老外为何在网络编程领域提出socket的概念了。估计老外也是根据插座提供电力这个想到的吧。
编辑于 2017-01-18