unix网络编程——TCP套接字编程
TCP客户端和服务端所需的基本套接字。服务器先启动,之后的某个时刻客户端启动并试图连接到服务器。之后客户端向服务器发送请求,服务器处理请求,并给客户端一个响应。该过程一直持续下去,直到客户端关闭,给服务端发送EOF(文件结束),服务器也关闭连接的服务器端,然后结束运行或者等待新的客户发起连接请求。如图1所示:
图1 TCP网络套接字示意图
在图中涉及到不同的函数,接下来进行详细的介绍。
socket函数
为了进行网络I/O,进程首先需要调用socket函数,指定使用的通信协议类型(IPv4的TCP、IPv6的UDP、Inux域字节流协议等)。
#include<sys/socket.h>
int socket(int family, int type, int protocol);
返回:若成功返回非负数,若失败返回-1
family表示协议族,协议族取值如表1所示:
family | 说明 |
AF_INET |
IPv4协议 |
AF_INET6 | IPv6协议 |
AF_LOCAL | Unix域协议 |
AF_ROUTE | 路由套接字 |
AF_KEY | 密钥套接字 |
表1 协议族family取值
type表示套接字类型,套接字类型type如表2所示:
type | 说明 |
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAM | 数据报套接字 |
SOCK_SEQPACKET | 有序分组套接字 |
SOCK_RAW | 原始套接字 |
表2 套接字类型
protocol表示某个协议类型常值,或者设置为0,以选择family和type组合的系统默认值,但并不是所有的family和type组合都是有效的,表3给出了正确组合。
表3 偷来的截图
socket函数调用成功后返回一个小的非负整数值,称为套接字描述符(socket descriptor),简称sockfd。指定了协议族(IPv4、Ipv6或Unix)和套接字类型(字节流、数据报或原始套接字),并没有指定本地协议地址或远程协议地址。
connect函数
TCP客户端使用connect函数来建立与TCP服务器之间的连接。
#include<sys/socket.h>
int connect(int sockfd, const struct *servaddr, socklen_t addrlen);
返回:若成功返回0,若失败返回-1
sockfd:socket函数返回的套接字描述符
servaddr:套接字地址结构的指针
addrlen:套接字地址结构的大小
套接字地址结构必须含有服务器的IP地址和端口号。客户端在调用connect函数前不必非要调用bind函数,因为如果需要的话,内核会确认源IP地址,并选择一个临时端口作为源端口。
如果是TCP套接字,调用connect函数会激发TCP三次握手,而且仅在连接建立成功或失败时才会返回。
bind函数
bind函数将一个本地协议地址赋予一个套接字,对于网际协议,协议地址是32位的Ipv4地址或128位的IPv6地址与16位的TCP或UDP端口号的组合。
#include<sys/socket.h>
int bind(int sockfd, const struct *myaddr, socklen_t addrlen);
返回:若成功返回0,若失败返回-1
sockfd:socket函数返回的套接字描述符
servaddr:套接字地址结构的指针
addrlen:套接字地址结构的大小
对于TCP,调用bind函数可以指定一个端口号和一个IP地址,也可以不指定。
服务器在启动时绑定它们的众所周知的端口,当调用connect或listen的时候,内核会为相应的套接字选择一个临时端口。让内核选择临时端口对于TCP客户端来说很正常,除非应用需要一个预留端口,然而对于TCP服务器来说却极为罕见,因为服务器是通过它们众所周知的端口被大家认识的。
(例外情况:RPC服务器,它们通常就由内核为它们的监听套接字选择一个临时端口,而该端口随后通过RPC端口映射器进行注册。客户在connect这些服务器之前,必须与端口映射器联系来获取它们的临时端口,这种情况也是用与UDP的RPC服务器)
进程可以将一个特定的IP地址绑定到它的套接字上,不过这个IP地址必须属于其所在主机的网络接口之一。对于TCP客户端,这就为在该套接字上发送的IP数据报指派了源IP地址,对于TCP服务器,这就限定该套接字只接收那些目的地为这个IP地址的客户连接。TCP客户通常不把IP地址绑定到套接字上。当连接套接字的时候,内核将根据所用外出网络接口选择源IP地址,而所有外出接口则取决于到服务器所需的路径。如果TCP服务器没有把IP地址绑定到套接字上,内核就把客户端发送的SYN的目的IP地址作为服务器的源IP地址。
如果指定端口为0,那么内核就在bind被调用时选择一个临时端口。然而如果指定IP地址为通配地址,那么内核将等到套接字已连接(TCP)或已在套接字上发出数据报(UDP)时才选择一个本地IP地址。
对于IPv4来说,通配地址由常值INADDR_ANY来指定,其值一般为0。它告知内核去选择IP地址。
listen函数
#include<sys/socket.h>
int listen(int sockfd, int backlog);
返回:若成功返回0,若失败返回-1
sockfd:socket函数返回的套接字描述符
backlog:内核应为响应套接字排队的最大连接个数
listen函数通常在调用socket函数和bind函数之后,调用accept函数之前调用。
listen函数仅由TCP服务器调用,它做两件事情:
当socket函数创建一个套接字的时候,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户端套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。调用listen函数使得套接字从CLOSED状态转到LISTEN状态。
图2 TCP状态转换图
为了理解backlog参数,必须为内核维护两个队列:
(1)未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中一项:已由某个客户端发起并达到服务器,而服务器正在等待完成相应的TCP三次握手过程。这些套接字处于SYN_RCVD状态(见图2);
(2)已完成连接队列(completed connection queue),每个已完成TCP三次握手过程的客户端对应其中一项,这些套接字处于ESTABLISHED状态(见图2)。
accept函数
accept函数由TCP服务器调用,用于从已完成连接队列的头部返回下一个已连接,如果已连接队列为空,那么进程休眠(如果套接字是默认的阻塞方式)。
#include<sys/socket.h>
int accept(int sockfd, struct *cliaddr, socklen_t *addrlen);
返回:若成功返回非负描述符,若失败返回-1
sockfd:socket函数返回的套接字描述符
cliaddr:返回已连接的对端(客户端)的协议地址
addrlen:值-结果参数(调用前,引用前,置为由cliaddr所指的套接字地址结构的长度,返回时,该整数值即为由内核存放在该套接字地址结构内的确切字节数)
fork和exec函数
fork函数是unix派生新进程的唯一方法。
#include<unistd.h>
pid_t fork(void);
返回:在子进程中为0,在父进程中为子进程ID,若失败返回-1
fork函数调用一次,会返回两次。在父进程(调用进程)中返回一次,返回值是子进程(新派生进程)的进程ID号;在子进程中又返回一次,返回值为0。因此可以通过返回值来确定是父进程还是子进程。
fork函数在父进程和子进程中返回值不同的原因:任何子进程只有一个父进程,而且子进程总是可以通过调用getppid取得父进程的进程ID,反之,父进程有很多子进程,而且无法获取各个子进程的进程ID。如果父进程想要追踪所有子进程的进程ID,那么必须记录每次调用fork的返回值(因为在每次调用fork的时候,父进程会返回子进程的ID号,如果每次都进行记录,那么就可以追踪所有子进程的进程ID)。
父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享,我们将看到网络服务器利用这个特性:父进程调用accept之后调用fork,所接受的已连接套接字随后在父进程和子进程之间共享。通常情况下,子进程接着读写这个已连接套接字,父进程则关闭这个已连接套接字。
fork的典型用法:
(1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。这是网络服务器的典型用法。
(2)一个进程想要执行另一个程序。既然创建新进程的唯一方法是调用fork,该进程于是首先调用fork创建一个自身副本,然后其中一个副本(通常称为子进程)调用exec把自身替换成新的程序,
unix网络编程——TCP套接字编程的更多相关文章
- 初探网络编程--TCP套接字编程演示
今天看了一下<计算机网络:自顶向下方法>,也就是计算机网络的教材的应用层一章,决定实现以下后面的Java C/S应用程序的例子,用来演示TCP和UDP套接字编程. 程序流程如下: 1.一台 ...
- 【UNIX网络编程(四)】TCP套接字编程具体分析
引言: 套接字编程事实上跟进程间通信有一定的相似性,可能也正由于此.stevens这位大神才会将套接字编程与进程间的通信都归为"网络编程",并分别写成了两本书<UNP1> ...
- UNP学习笔记1——基本TCP套接字编程
1 套接字地址结构 大多数套接字函数都需要一个指向套接字地址结构的指针作为参数.每个协议族都定义了自己的套接字结构.这些套接字的结构以sockaddr_开头,以每个协议族唯一的后缀名结尾. 1.1 I ...
- TCP套接字编程模型及实例
摘要: 本文讲述了TCP套接字编程模块,包括服务器端的创建套接字.绑定.监听.接受.读/写.终止连接,客户端的创建套接字.连接.读/写.终止连接.先给出实例,进而结合代码分析. PS:本文权当 ...
- 【UNIX网络编程(二)】基本TCP套接字编程函数
基于TCP客户/server程序的套接字函数图例如以下: 运行网络I/O.一个进程必须做的第一件事就是调用socket函数.指定期望的通信协议类型. #include <sys/socket.h ...
- unix网络编程第四章----基于TCP套接字编程
为了执行网络I/O操作.进程必须做的第一件事情就是调用Socket函数.指定期待的通信协议 #include<sys/socket.h> int socket(int family,int ...
- <网络编程>基本TCP套接字编程
tcp提供了可靠传输,当tcp向另一端发送数据的时候,要求对端返回一个确认.如果没有接收到确认,tcp就重传数据并且等待更长时间,数次重传失败后,tcp才放弃. 建立一个tcp连接会发生如下事情: 服 ...
- <unix网络编程>UDP套接字编程
典型的UDP客户/服务器程序的函数调用如下: 1.缓冲区 发送缓冲区用虚线表示,任何UDP套接字都有发送缓冲区,不过该缓冲区仅能表示写到该套接字的UDP数据报的上限.如果应用进程写一个大于套接字缓冲区 ...
- 套接字编程相关函数(2:TCP套接字编程相关函数)
本文摘录自<UNIX网络编程 卷1>. 基本套接字函数 socket函数 为了执行网络I/O,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型.其定义如下: #in ...
随机推荐
- Phpstorm如何连接服务器
当服务器是Linux的时候不懂指令觉得很懊恼,这个时候直接就可以使用PHPstorm连接服务器操作了: 1丶准备工作 首先你先要准备服务器丶phpstorm这两个吧! 2丶开始配置phpstorm 按 ...
- Scala的高级特性
高阶函数 概念 Scala混合了面向对象和函数式的特性,我们通常将可以作为参数传递到方法中的表达式叫做函数.在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数.匿名函数.闭包.柯里化等 ...
- 20145209刘一阳《JAVA程序设计》第七周课堂测试
第七周课堂测试 1.命令"CREATE DATABASE "用来创建一个数据库.(A) A .true B .false 2.以下不属于驱动的四种类型的是(C) A .JDBC-O ...
- 6-[HTML]-标签属性
1.HTML标签属性 HTML标签可以设置属性,属性一般以键值对的方式写在开始标签中.如 <div id="i1">这是一个div标签</div> < ...
- 【LG3240】[HNOI2015]实验比较
题面 洛谷 题解 30pts 爆搜即可. 100pts 题意描述里有一句:"对每张图片\(i\),小\(D\)都最多只记住了某一张质量不比\(i\)差的另一张图片\(K_i\)." ...
- Introduction to Big Data with PySpark
起因 大数据时代 大数据最近太热了,其主要有数据量大(Volume),数据类别复杂(Variety),数据处理速度快(Velocity)和数据真实性高(Veracity)4个特点,合起来被称为4V. ...
- 【转】阿里云Linux系统被攻击的处理过程
4-22日 19:48分,在等女儿跳舞下课的时候,在“多看”进入大刘等人的<毁灭之城:地球碎块>,读到了“诅咒 3.0”病毒出现的时候,阿里云发来短信“尊敬的用户,您的云服务器x.x.x. ...
- ES6的promise函数用法讲解
总结:Promise函数的出现极大的解决了Js中的异步调用代码逻辑编写太过复杂的问题,Promise对象让异步调用函数的流程显得更加的优雅,也更容易编写. 举例: 1. 异步调用: 假设现在我的一个页 ...
- [环境配置]Ubuntu16.04下编译安装gcc6.3.0
上一篇的SVS要用gcc6.3编译,否则结果不正确,本来以为gcc很好装,结果发现用apt-get安装gcc6只能安装6.5版本,代码作者奇特的要求只能用gcc6.3,没办法只能用源码装了,期间碰见了 ...
- Unity萌新日记—开发小技巧与冷知识(脚本篇)
在学习unity的过程中,总会遇到很多零碎的知识点和小技巧,在此把它们记录下来,方便日后查看. 第一篇是关于脚本的一些你可能不知道的小知识. 还是个正在学习的萌新,如果写的不好,请谅解. Unity版 ...