什么是Socket
socket监听原理

socket监听原理一、什么是socket监听在计算机网络通信中,套接字(socket)是一种用于进行网络通信的工具。
通过套接字,计算机之间可以建立双向的通信连接,实现数据的传输和交换。
监听是套接字的一种工作模式,通过监听,套接字可以在指定的端口上等待其他计算机发送的连接请求。
一旦有连接请求到达,套接字就会接受该连接并与对方建立通信。
二、socket监听的原理在进行socket监听的过程中,我们需要关注以下几个核心点:1.端口号2.IP地址3.协议2.1 端口号在网络通信中,每个应用程序都需要通过指定一个端口号来进行通信。
端口号是一个16位的整数,取值范围是0-65535。
常见的端口号被分为三大类:系统端口(0-1023)、用户端口(1024-49151)和动态/私有端口(49152-65535)。
监听过程中,我们会指定一个端口号进行监听,以便其他计算机可以通过该端口号与我们进行通信。
2.2 IP地址IP地址是用于唯一标识一台计算机的地址。
在进行socket监听时,我们需要指定监听的IP地址,以便其他计算机可以通过该地址找到我们。
常见的IP地址分为两类:IPv4和IPv6。
IPv4地址由32位二进制数组成,用四个十进制数表示,如192.168.0.1;IPv6地址由128位二进制数组成,用八组十六进制数表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。
2.3 协议在进行socket监听时,我们需要选择合适的协议进行通信。
常用的协议有TCP和UDP。
•TCP(Transmission Control Protocol,传输控制协议)是一种可靠的、面向连接的协议。
在TCP连接中,通信双方将建立起一条连接,通过该连接进行可靠的数据传输。
•UDP(User Datagram Protocol,用户数据报协议)是一种不可靠的、无连接的协议。
在UDP连接中,数据包可以直接发送给目标地址,不需要建立连接。
TCP,UDP,Socket,Http网络编程面试题 47道

TCP/IP参考模型TCP/IP四层协议(数据链路层、网络层、传输层、应用层)1. 应用层应用层最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。
我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,TELNET等。
2. 传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。
该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。
我们通常说的,TCP UDP就是在这一层。
端口号既是这里的“端”。
3. 网络层本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。
就是通常说的IP层。
这一层就是我们经常说的IP协议层。
IP协议是Internet的基础。
4. 数据链路层通过一些规程或协议来控制这些数据的传输,以保证被传输数据的正确性。
实现这些规程或协议的硬件和软件加到物理线路,这样就构成了数据链路,1 TCP / UDP1. 第一次握手:Client将SYN置1,随机产生一个初始序列号seq发送给Server,进入SYN_SENT状态;2. 第二次握手:Server收到Client的SYN=1之后,知道客户端请求建立连接,将自己的SYN置1,ACK置1,产生一个acknowledge number=sequence number+1,并随机产生一个自己的初始序列号,发送给客户端;进入SYN_RCVD状态;3. 第三次握手:客户端检查acknowledge number是否为序列号+1,ACK是否为1,检查正确之后将自己的ACK置为1,产生一个acknowledge number=服务器发的序列号+1,发送给服务器;进入ESTABLISHED状态;服务器检查ACK为1和acknowledge number为序列号+1之后,也进入ESTABLISHED状态;完成三次握手,连接建立。
通俗大白话来理解TCP协议的三次握手和四次分手

通俗⼤⽩话来理解TCP协议的三次握⼿和四次分⼿通俗理解:但是为什么⼀定要进⾏三次握⼿来保证连接是双⼯的呢,⼀次不⾏么?两次不⾏么?我们举⼀个现实⽣活中两个⼈进⾏语⾔沟通的例⼦来模拟三次握⼿。
引⽤⽹上的⼀些通俗易懂的例⼦,虽然不太正确,后⾯会指出,但是不妨碍我们理解,⼤体就是这么个理解法。
第⼀次对话:⽼婆让甲出去打酱油,半路碰到⼀个朋友⼄,甲问了⼀句:哥们你吃饭了么?结果⼄带着⽿机听歌呢,根本没听到,没反应。
甲⼼⾥想:跟你说话也没个⾳,不跟你说了,沟通失败。
说明⼄接受不到甲传过来的信息的情况下沟通肯定是失败的。
如果⼄听到了甲说的话,那么第⼀次对话成功,接下来进⾏第⼆次对话。
第⼆次对话:⼄听到了甲说的话,但是他是⽼外,中⽂不好,不知道甲说的啥意思也不知道怎样回答,于是随便回答了⼀句学过的中⽂:我去厕所了。
甲⼀听⽴刻笑喷了,“去厕所吃饭”?道不同不相为谋,离你远点吧,沟通失败。
说明⼄⽆法做出正确应答的情况下沟通失败。
如果⼄听到了甲的话,做出了正确的应答,并且还进⾏了反问:我吃饭了,你呢?那么第⼆次握⼿成功。
通过前两次对话证明了⼄能够听懂甲说的话,并且能做出正确的应答。
接下来进⾏第三次对话。
第三次对话:甲刚和⼄打了个招呼,突然⽼婆喊他,“你个死⿁,打个酱油咋这么半天,看我回家咋收拾你”,甲是个妻管严,听完吓得⼆话不说就跑回家了,把⼄⾃⼰晾那了。
⼄⼼想:这什么⼈啊,得,我也回家吧,沟通失败。
说明甲⽆法做出应答的情况下沟通失败。
如果甲也做出了正确的应答:我也吃了。
那么第三次对话成功,两⼈已经建⽴起了顺畅的沟通渠道,接下来开始持续的聊天。
通过第⼆次和第三次的对话证明了甲能够听懂⼄说的话,并且能做出正确的应答。
可见,两个⼈进⾏有效的语⾔沟通,这三次对话的过程是必须的。
为了保证服务端能收接受到客户端的信息并能做出正确的应答⽽进⾏前两次(第⼀次和第⼆次)握⼿,为了保证客户端能够接收到服务端的信息并能做出正确的应答⽽进⾏后两次(第⼆次和第三次)握⼿。
rawsocket编程讲解

网络协议回顾对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。
那么我想问:1. 什么是TCP/IP、UDP?2. Socket在哪里呢?3. Socket是什么呢?4. 你会使用它们吗?什么是TCP/IP、UDP?TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
UDP(User Data Protocol,用户数据报协议)是与TCP 相对应的协议。
它是属于TCP/IP协议族中的一种。
这里有一张图,表明了这些协议的关系。
TCP/IP协议族包括运输层、网络层、链路层。
现在你知道TCP/IP与UDP的关系了吧。
ICMP协议格式ICMP协议有两种类型:查询报文和差错报文。
其格式如下:差错报文中,Type是差错类型;Code是差错类型中的子类型;Checksum是ICMP的校验和(校验和覆盖ICMP的头和数据)。
其数据部分包含出错包的IP头(包括选项)和IP数据的前八个字节。
地址伪装只处理三种协议(ICMP,TCP,UDP)的差错包,并且只处理三种类型的差错报文,如下:ICMP_DEST_UNREACH(目的不可达),ICMP_SOURCE_QUENCH(源端被关闭),ICMP_TIME_EXCEEDED(超时)。
差错报文中,Type是差错类型;Code是差错类型中的子类型;Checksum是ICMP的校验和(校验和覆盖ICMP的头和数据)。
其数据部分包含出错包的IP头(包括选项)和IP数据的前八个字节。
地址伪装只处理三种协议(ICMP,TCP,UDP)的差错包,并且只处理三种类型的差错报文,如下:ICMP_DEST_UNREACH(目的不可达),ICMP_SOURCE_QUENCH(源端被关闭),ICMP_TIME_EXCEEDED(超时)。
什么是socket?什么是websocket?两者有什么区别?

什么是socket?什么是websocket?两者有什么区别?HTML5规范在传统的web交互基础上为我们带来了众多的新特性,随着web技术被⼴泛⽤于web APP的开发,这些新特性得以推⼴和使⽤,⽽websocket作为⼀种新的web通信技术具有巨⼤意义。
什么是socket?什么是websocket?两者有什么区别?websocket是仅仅将socket的概念移植到浏览器中的实现吗?我们知道,在⽹络中的两个应⽤程序(进程)需要全双⼯相互通信(全双⼯即双⽅可同时向对⽅发送消息),需要⽤到的就是socket,它能够提供端对端通信,对于程序员来讲,他只需要在某个应⽤程序的⼀端(暂且称之为客户端)创建⼀个socket实例并且提供它所要连接⼀端(暂且称之为服务端)的IP地址和端⼝,⽽另外⼀端(服务端)创建另⼀个socket并绑定本地端⼝进⾏监听,然后客户端进⾏连接服务端,服务端接受连接之后双⽅建⽴了⼀个端对端的TCP连接,在该连接上就可以双向通讯了,⽽且⼀旦建⽴这个连接之后,通信双⽅就没有客户端服务端之分了,提供的就是端对端通信了。
我们可以采取这种⽅式构建⼀个桌⾯版的im程序,让不同主机上的⽤户发送消息。
从本质上来说,socket并不是⼀个新的协议,它只是为了便于程序员进⾏⽹络编程⽽对tcp/ip协议族通信机制的⼀种封装。
websocket是html5规范中的⼀个部分,它借鉴了socket这种思想,为web应⽤程序客户端和服务端之间(注意是客户端服务端)提供了⼀种全双⼯通信机制。
同时,它⼜是⼀种新的应⽤层协议,websocket协议是为了提供web应⽤程序和服务端全双⼯通信⽽专门制定的⼀种应⽤层协议,通常它表⽰为:ws:///?encoding=text HTTP/1.1,可以看到除了前⾯的协议名和http不同之外,它的表⽰地址就是传统的url地址。
可以看到,websocket并不是简单地将socket这⼀概念在浏览器环境中的移植,本⽂最后也会通过⼀个⼩的demo来进⼀步讲述socket和websocket在使⽤上的区别。
TCP与UDP必考题

问题及解答:1.端口(port)和套接字(socket)的区别是什么?2.是否TCP和UDP都需要计算往返时间RTT?3.在TCP传送数据时,有没有规定一个最大重传次数?4.为什么TCP在建立连接时不能每次都选择相同的、固定的初始序号?5.TCP连接很像一条连接发送端和接收端的双向管道。
当TCP在连续发送报文段时,若要管道得到充分的利用,则发送窗口的大小应怎样选择?6.TCP发送方和接收方都需要滑动窗口吗?各有什么作用?7.滑动窗口的窗口大小可以动态调整吗?调整窗口大小可以起到什么作用?8.在UDP协议中需要滑动窗口协议吗?为什么?这样有什么好处有什么坏处?1.端口(port)和套接字(socket)的区别是什么?答:套接字包含了端口,因为套接字= (IP地址,端口号)。
套接字是TCP连接的端点。
套接字又称为“插口”。
但我们已经讲过,套接字(socket)有多种意思。
当使用API时,套接字往往被看成是操作系统的一种抽象,这时,套接字和一个文件描述符是很相似的,并且是应用编程接口API 的一部分。
套接字由应用程序产生,并指明它将由客户还是服务器来使用。
当应用进程创建一个套接字时,要指明该套接字使用的端口号。
端口则是应用层服务的的一种代号,它用来标志应用层的进程。
端口是一个16 bit的整数。
各种服务器使用的端口号都是保留端口号,以便使客户能够找到服务器。
例如万维网服务器使用的端口号是80。
在发送数据时,应用层的数据通过端口向下交付到运输层。
在接收数据时,运输层的数据通过适当的端口向上交付到应用层的某个应用程序2.是否TCP和UDP都需要计算往返时间RTT?答:TCP有的,UDP没有的,UDP发出去其实就不管了,它是需要在应用软件(应用层)来做一个数据传送保障的机制的。
重发也是通过软件端实现。
TCP本身协议就具有保障数据的功能。
3.在TCP传送数据时,有没有规定一个最大重传次数?答:我们知道以太网规定重传16次就认为传输失败,然后报告上层。
socket通信的原理

socket通信的原理一、什么是Socket通信?Socket通信是指在网络上两个计算机之间进行双向的数据传输。
它是一种可靠的、可靠的、可伸缩的、可伸缩的、可伸缩的IP网络通信台式机的标准。
二、Socket通信的原理Socket通信有两个连接对象:客户端和服务器端。
客户端通过它的Socket向服务器端发送消息,服务器端则使用它的Socket来监听客户端的消息,当收到消息时,服务器端就会进行响应。
客户端和服务器端之间的Socket通信分为两个阶段:首先是Socket链接的建立,其次是Socket数据传输。
1、链接建立客户端会先启动一个链接,发出一个接收连接的请求到服务器端,请求的信息被称之为Syn(Synchronize)报文。
服务器端收到Syn报文后,会向客户端发出确认报文,称为Syn-Ack(Synchronize-Acknowledgment)报文,之后客户端会发出Ack (Acknowledgment)报文,完成三次握手,此时Socket链接已建立完成。
2、数据传输当客户端链接建立完成后,就可以通过Socket进行双向的数据传输。
数据传输的过程就像两个人在使用电话一样,只需要将自己的消息发送给对方,对方就可以接收到消息。
三、Socket通信的优势Socket通信和其它网络通信有很多优势:1、高效:Socket通信的数据通讯效率高,接近本地通讯;2、可靠:Socket通信是可靠的网络通讯方式,比如它可以在网络中传播压缩或加密的消息;3、安全:Socket通信是经过加密的,可以保证消息不会被篡改或拦截;4、易用:Socket通信可以支持跨平台,不同的操作系统间都可以进行连接;5、可扩展性:Socket通信可以轻松扩展应用,不会影响之前的连接和功能。
socket是什么协议

socket是什么协议Socket是一种通信协议,它是在网络编程中非常重要的一部分。
它允许不同的计算机之间进行通信,使得数据能够在网络中传输。
在本文中,我们将探讨Socket 是什么协议,以及它在网络编程中的作用。
首先,让我们来了解一下Socket的基本概念。
Socket可以被看作是一种通信的端点,它可以在网络中的两台计算机之间建立连接,并且使它们能够进行数据的交换。
在网络编程中,Socket通常被用来建立客户端和服务器之间的连接,使它们能够进行数据的传输和交换。
Socket协议是基于TCP/IP协议栈的,它使用IP地址和端口号来标识网络中的不同计算机和服务。
通过Socket,计算机之间可以建立可靠的连接,并且进行数据的传输。
它提供了一种双向通信的机制,使得客户端和服务器之间能够进行实时的数据交换。
在网络编程中,Socket通常被用来实现各种不同的网络应用,比如网页浏览器、邮件客户端、文件传输等。
它为这些应用提供了一种通用的通信机制,使得它们能够在网络中进行数据的传输和交换。
Socket协议在网络编程中扮演着非常重要的角色。
它为不同的计算机和应用提供了一种通用的通信机制,使得它们能够在网络中进行数据的传输。
通过Socket,我们可以实现各种不同的网络应用,使得它们能够在网络中进行实时的数据交换。
总之,Socket是一种非常重要的通信协议,它在网络编程中扮演着非常重要的角色。
它为不同的计算机和应用提供了一种通用的通信机制,使得它们能够在网络中进行数据的传输和交换。
通过Socket,我们可以实现各种不同的网络应用,使得它们能够在网络中进行实时的数据交换。
希望本文对您有所帮助,谢谢阅读!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
什么是SocketSocket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。
要学Internet上的TCP/IP网络编程,必须理解Socket接口。
Socket接口设计者最先是将接口放在Unix操作系统里面的。
如果了解Unix系统的输入和输出的话,就很容易了解Socket了。
网络的 Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。
Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
常用的Socket类型有两种:流式Socket (SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。
流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
Socket建立为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。
socket函数原型为:int socket(int domain, int type, int protocol);domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket (SOCK_RAW),允许程序使用低层协议;protocol通常赋值"0"。
Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。
Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。
调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。
Socket执行体为你管理描述符表。
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。
Socket数据结构中包含这五种信息。
Socket配置通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。
面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。
无连接socket的客户端和服务端以及面向连接socket的服务端通过调用 bind函数来配置本地信息。
Bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。
Bind函数原型为:int bind(int sockfd,struct sockaddr *my_addr, int addrlen);Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。
struct sockaddr结构类型是用来保存socket信息的:struct sockaddr {unsigned short sa_family; /* 地址族, AF_xxx */char sa_data[14]; /* 14 字节的协议地址 */};sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket 的IP地址和端口号。
另外还有一种结构类型:struct sockaddr_in {short int sin_family; /* 地址族 */unsigned short int sin_port; /* 端口号 */struct in_addr sin_addr; /* IP地址 */unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */};这个结构更方便使用。
sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。
指向sockaddr_in 的指针和指向sockaddr 的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。
同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。
注意在使用bind函数是需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_addr 则不需要转换。
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。
Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。
下面是几个字节顺序转换函数:·htonl():把32位值从主机字节序转换成网络字节序·htons():把16位值从主机字节序转换成网络字节序·ntohl():把32位值从网络字节序转换成主机字节序·ntohs():把16位值从网络字节序转换成主机字节序Bind()函数在成功被调用时返回0;出现错误时返回"-1"并将errno置为相应的错误号。
需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。
连接建立面向连接的客户程序使用Connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为:int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);Sockfd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地质结构的长度。
Connect函数在出现错误时返回-1,并且设置errno为相应的错误码。
进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP 地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候到打断口。
Connect函数启动和远端主机的直接连接。
只有面向连接的客户程序使用socket时才需要将此socket与远端主机相连。
无连接协议从不建立直接连接。
面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客户的请求。
Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。
int listen(int sockfd, int backlog);Sockfd 是Socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们(参考下文)。
Backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。
如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息。
当出现错误时listen函数返回-1,并置相应的errno错误码。
accept()函数让服务器接收客户的连接请求。
在建立好输入队列后,服务器就调用accept 函数,然后睡眠并等待客户的连接请求。
int accept(int sockfd, void *addr, int *addrlen);sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。
出现错误时accept函数返回-1并置相应的errno值。
首先,当accept函数监视的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket 仍可以继续在以前的 socket上监听,同时可以在新的socket描述符上进行数据传输操作。
数据传输Send()和recv()这两个函数用于面向连接的socket上进行数据传输。
Send()函数原型为:int send(int sockfd, const void *msg, int len, int flags);Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。
Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。
在程序中应该将send()的返回值与欲发送的字节数进行比较。
当send()返回值与len不匹配时,应该对这种情况进行处理。
char *msg = "Hello!";int len, bytes_sent;……len = strlen(msg);bytes_sent = send(sockfd, msg,len,0);……recv()函数原型为:int recv(int sockfd,void *buf,int len,unsigned int flags);Sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。
Flags也被置为0。
Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno 值。