Python的网络编程,模型理解
分类:web前端

环境:Win10    python

一、socket

Android NDK开拓之旅 目录

Socket

  • 3.7

  平时的话socket有贰个外号也叫做套接字。

前言

我们做前端开荒首要用http/https央求,这种乞请从数额更新角度是单向的,即客商发起倡议技能取得到最新数据。但有的时候候,一些情状和数指标校订要马上推送到前面一个。比方O2O行业,消费者下定单 -> O2O小卖部接收到订单 -> 送外送食品小哥即时接到订单-> 消费者实时收到外送食物小哥和温馨的间距。
内部,后两步要即时选用新闻,就得利用 Socket编制程序保持长连接。再举个例子,新闻推送,语音闲扯等。

注意:
HTTP也能够建构长连接的,使用Connection:keep-alive,HTTP 1.1暗许进行一心一德连接。HTTP1.1和HTTP1.0相相比来说,最大的区分正是增多了漫长连接援助(貌似新颖的 http1.0 能够来得的内定keep-aliveState of Qatar,但依然无状态的,或然说是不得以相信的。


Socket工作原理和基本概念

  socket起点于Unix,都能够用“打 开open –> 读写write/read –> 关闭close”形式来操作。Socket就是该形式的三个落到实处,socket正是一种特有的公文,一些socket函数正是对其打开的操作(读/写 IO、展开、关闭)。

1、网络中经过之间怎样通讯?

地面包车型客车长河间通讯(IPC)有很种种方法,但足以总括为上面4类:

  • 音讯传递(管道、FIFO、音信队列)
  • 联合(互斥量、条件变量、读写锁、文件和写记录锁、复信号量)
  • 分享内部存款和储蓄器(无名的和签名的)
  • 长途进度调用(Solaris门和Sun RPC)

互联网中经过之间怎么通讯?
重视消除的标题是何许独一标志一个历程,不然通讯无从聊起!在本土能够通过进程PID来独一标志三个进度,可是在互连网中这是不行的。其实TCP/IP协议族已经帮大家减轻了那一个主题素材,互连网层的“ip地址”可以独一标志互连网中的主机,而传输层的“合同+端口”能够独一标志主机中的应用程序(进程)。那样利用安慕希组(ip地址,合同,端口)就足以标识互连网的进度了,互连网中的进度通讯就能够使用那么些标识与其它进度张开相互。

采用TCP/IP合同的应用程序平日选用选择编制程序接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来得以实现互连网进度之间的通信。
就当下来说,大约全数的应用程序都以接收socket,而后天又是互联网时代,互连网中经过通讯是无处不在,那正是自家怎么说“一切皆socket”。

 目录

        Socket的普通话翻译是套接字,它是TCP/IP网络情状下应用程序与底层通讯驱动程序之间运转的付出接口,它能够将应用程序与现实的TCP/IP隔开分离开来,使得应用程序无需精通TCP/IP的如闻其声细节,就可以知道贯彻数据传输。

  说白了Socket是应用层与TCP/IP 公约族通讯的中档软件抽象层,它是一组接口。在设计方式中,Socket其实正是八个外衣形式,它把纷纭的TCP/IP协议族掩瞒在Socket接口后面,对客户来讲,一组轻易的接口正是全方位,让Socket去协会数量,以切合钦定的协商,而无需让客户本身去定义哪天供给钦命哪个左券哪个函数。

2. Socket是什么

  1. socket 的 TCP/IP 通讯基本确立进程
  2. socket 的 UDP 通讯基本确立进程
  3. socket 的 UDP 广播式通讯基本创设进程
  4. socket 的三十二线程通讯建构过程

         在网络应用程序中,Socket通讯是依附客商端/服务器布局。顾客端是发送数据的一方。服务器时刻筹算选取来自顾客端的数量,对做出响应.

    其实socket也未尝层的定义,它只是三个facade设计形式的采取,让编程变的更简明。是一个软件抽象层。在互连网编制程序中,大家大量用的都以经过socket达成的。

2.1 socket套接字:

socket起点于Unix,而Unix/Linux基本理学之一就是“一切皆文件”,都能够用“展开open –> 读写write/read –> 关闭close”方式来操作。Socket正是该模式的三个落实, socket便是一种特有的公文,一些socket函数正是对其举行的操作(读/写IO、张开、关闭).
总的来讲Socket是应用层与TCP/IP公约族通讯的高级中学级软件抽象层,它是一组接口。在设计格局中,Socket其实正是八个伪装方式,它把纷纭的TCP/IP左券族隐敝在Socket接口后边,对顾客来讲,一组大约的接口便是百分百,让Socket去组织数量,以相符钦点的商业事务。

在意:其实socket也尚无层的定义,它只是一个facade设计情势的选拔,让编制程序变的更简便易行。是一个软件抽象层。在互连网编制程序中,大家一大波用的都以经过socket完成的。

  

兑现基于tcp网络通讯与现实中打电话很像:

1.1套接字描述符

2.2、套接字描述符

实则就是二个偏分头,我们最熟稔的句柄是0、1、2四个,0是正统输入,1是正统输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE *布局的意味正是stdin、stdout、stderr

套接字API最先是用作UNIX操作系统的一片段而开垦的,所以套接字API与系统的别的I/O设备集成在协同。特别是,当应用程序要为因特网通讯而创造叁个套接字(socket)时,操作系统就回去二个小板寸作为描述符(descriptor)来标志那个套接字。然后,应用程序以该描述符作为传递参数,通过调用函数来完毕某种操作(比如通过互连网传送数据或抽取输入的多少)。

在广大操作系统中,套接字描述符和其他I/O描述符是集成在一齐的,所以应用程序能够对文件实行套接字I/O或I/O读/写操作。

当应用程序要开创三个套接字时,操作系统就回来一个小板寸作为描述符,应用程序则动用这些描述符来援用该套接字须要I/O诉求的应用程序央求操作系统张开二个文书。操作系统就创办叁个文书呈报符提须要应用程序访谈文件。从应用程序的角度看,文件汇报符是叁个整数,应用程序可以用它来读写文件。下图展示,操作系统怎么着把文件陈说符达成为三个指针数组,那个指针指向里面数据结构。

对此各样程序系统都有一张单独的表。准确地讲,系统为种种运转的长河维护一张单独的文件叙述符表。当进程张开四个文件时,系统把三个针对此文件之中数据构造的指针写入文件陈诉符表,并把该表的索引值再次来到给调用者 。应用程序只需记住那几个描述符,并在后头操作该公文时使用它。操作系统把该描述符作为目录访谈进程描述符表,通过指针找到保存该公文全部的消息的数据构造。

针对套接字的系统数据构造:

1)、套接字API里有个函数socket,它正是用来创立叁个套接字。套接字设计的一体化思路是,单个系统调用就足以创立任何套接字,因为套接字是一定笼统的。一旦套接字创制后,应用程序还亟需调用别的函数来内定具体细节。比方调用socket将创设二个新的描述符条约:

2)、即便套接字的此中数据构造包罗众多字段,不过系统成立套接字后,大好多字字段未有填写。应用程序创制套接字后在该套接字能够选取此前,必得调用别的的经过来填充这几个字段。

1 socket的TCP/IP通讯基本确立进度

1State of Qatar      客商端(也正是打电话的一方),需求掌握服务器的ip地址,若是该服务器有多个网络应用程序,单单ip地址则非常不够,那时socket通讯借用tcp/ip中端口的定义,分化应用程序使用差别端口通信(那就很相近电话分机)。

  其实正是三个整数,大家最谙习的句柄是0、1、2多少个,0是正规输入,1是正规输出,2是正式错误输出。0、1、2是整数表示的,对应的FILE *构造的表示正是stdin、stdout、stderr

3、基本的socket接口函数

 服务器端先早先化/创制Socket,然后与端口绑定/绑定地址(bind卡塔尔,对端口实行监听(listen卡塔尔,调用accept梗塞/等待三翻五次,等待客商端连接。在这里儿若是有个顾客端起头化二个Socket,然后连接服务器(connect卡塔尔,假使老是成功,这时候客商端与服务器端的连续几天就确立了。客商端发送数据央求,服务器端选择须求并管理央求,然后把应对数据发送给顾客端,顾客端读取数据,最后关闭连接,一遍交互作用结束。

socket的TCP/IP通讯连接首要归纳多少个部分,服务端与客商端

2卡塔尔(قطر‎      服务器应用程序必须早于客商端运营,并在内定ip地址和端口上实行监听,端口被占用,服务器则不大概寻常运维。(服务器处于监听状态就犹如电话接通好电话线,等待被拨打大巴情景)

  套接字API最早是充当UNIX操作系统的一有的而付出的,所以套接字API 与系统的此外I/O设备集成在联名。特别是,当应用程序要为因特网通讯而创制二个套接字(socket)时,操作系统就回来三个小子弹头作为描述符 (descriptor)来标记这几个套接字。然后,应用程序以该描述符作为传递参数,通过调用函数来成功某种操作(比如通过互联网传送数据或选用输入的数 据)。

3.1、socket函数

函数原型:

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

返回值:
  //重回sockfd sockfd是描述符,雷同于open函数。

函数功效:

socket函数对应于普通文书的开发操作。普通文书的开采操作再次来到叁个文本陈诉字,而socket(卡塔尔(قطر‎用于创制三个socket描述符(socket descriptor),它独一标志叁个socket。这一个socket描述字跟文件陈说字同样,后续的操作都有使用它,把它充任参数,通过它来举香港行政局地读写操作。

函数参数:

protofamily:即左券域,又称作家协会议族(family)。常用的公约族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。合同族决定了socket的地点类型,在通讯中必得使用对应之处,如AF_INET决定了要用ipv4地址(三12人的)与端口号(18个人的)的重新组合、AF_UNIX决定了要用一个绝对路线名作为地点。

1.1 Socket server服务端建构

3卡塔尔国      客商端在申请发送数据时,服务器端应用程序必须有丰硕的年华响应本事开展常规通讯(电话响,却无人接听)。通常意况下,服务器的应用程序都急需全数同有时间管理四个客商端央浼的力量,应用程序设计不客观或访谈量过高都会导致响应超时。

  在无数操作系统中,套接字描述符和别的I/O描述符是集成在一同的,所以应用程序能够对文件实行套接字I/O或I/O读/写操作。

3.2、bind()函数

函数功用:
  bind(卡塔尔(قطر‎函数把二个地址族中的特定地方赋给socket,也足以说是绑定ip端口和socket。举个例子对应AF_INET、AF_INET6就是把叁个ipv4或ipv6地址和端口号组合赋给socket。

函数原型:

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数参数:

  1. 函数的八个参数分别为:sockfd:即socket描述字,它是通过socket(卡塔尔函数创立了,独一标志三个socket。bind(卡塔尔国函数就是将给这几个描述字绑定一个名字。
  2. addr:一个const struct sockaddr *指南针,指向要绑定给sockfd的商业事务地址。那一个地点构造办事处点创立socket时的地点公约族的不如而各异,
  3. addrlen:对应的是地方的尺寸。

服务端组建步骤首要有:

4卡塔尔国      使用Socket契约举办通讯的两方必须运用相似的通讯合同,Socket扶持的底层通讯协议包蕴tcp和udp三种,通讯过程中,两方还必得利用相仿的字符编码,依照约定的方法开展通讯(打电话时,两方必得语言相通,技巧开展消息交换)

  当应用程序要制造一个套接字时,操作系统就回来壹个小莫西干发型作为描述符,应用程 序则应用那一个描述符来援用该套接字需求I/O央浼的应用程序央浼操作系统展开三个文书。操作系统就创造一个文本呈报符提要求应用程序访谈文件。从使用程序 的角度看,文件呈报符是二个子弹头,应用程序能够用它来读写文件。下图显示,操作系统怎样把文件陈说符完结为三个指南针数组,那个指针指向在那之中数据结构。

3.3、listen()、connect()函数

函数功用:
  假如作为叁个服务器,在调用socket(卡塔尔国、bind(卡塔尔之后就能够调用listen(卡塔尔来监听那个socket,假诺顾客端那个时候调用connect(卡塔尔(قطر‎发出连接央浼,服务器端就能抽出到这几个央浼。
函数原型:

  int listen(int sockfd, int backlog);
  int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数参数:
  listen函数的首先个参数即为要监听的socket描述字,第一个参数为对应socket能够排队的最达累斯萨拉姆接个数。socket(卡塔尔(قطر‎函数成立的socket默许是三个积极性类型的,listen函数将socket变为被动类型的,等待客商的连续几日须求。
  connect函数的首先个参数即为顾客端的socket描述字,第二参数为服务器的socket地址,第两个参数为socket地址的长短。客商端通过调用connect函数来营造与TCP服务器的总是。成功再次回到0,若总是退步则赶回-1。

  1. 初阶化IP地址和端口号;
  2. 生成socket实例,TCP/IP通讯选拔AF_INET(IPV4),SOCK_STREAM(流套接字类型,数据像字符流同样通过);
  3. bind(卡塔尔函数绑定IP和端口,listen(State of Qatar函数设置最大监听数据;
  4. accept(卡塔尔(قطر‎函数选取client的三番四次,对于接二连三的client重临2个参数cs,addr,cs为一个新变化的socket类,用于与连接的client举办电视发表,addr富含IP和端口号消息;
  5. 基于生成的cs与client实行广播发表。

    1 # server 2 3 import socket 4 # set IP and Port 5 address = ('127.0.0.1', 31500) 6 # choose IPV4, stream type 7 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 # bind address and ip 9 s.bind(address) 10 # allow max five connection 11 s.listen(5)
    12 13 while True: 14 # wait client's request, cs is a new socket object and server use it to communicate with client 15 cs, address = s.accept()
    16 print('got connected from', address) 17 # send message to client 18 cs.send(b'hello I am server, welcome') 19 # receive message from client and decode 20 re = cs.recv(1024).decode('utf-8')
    21 print(re) 22 cs.close()

5State of Qatar      通讯时,物理网络必须维持交通,否则通讯将会停顿(电电话线有效,且一而再通常)。

图片 1

3.4、accept()函数

函数功效:
  TCP服务器端依次调用socket(卡塔尔国、bind(State of Qatar、listen(卡塔尔(قطر‎之后,就能够监听钦命的socket地址了。TCP客商端依次调用socket(State of Qatar、connect(卡塔尔之后就向TCP服务器发送了五个接二连三乞求。TCP服务器监听到这些要求之后,就能调用accept(卡塔尔国函数取接受央求,那样总是就确立好了。之后就可以初始互连网I/O操作了,几天前常于平日文书的读写I/O操作。
函数原型:

  int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接connect_fd

函数参数:
sockfd:
  参数sockfd正是地点表明中的监听套接字,这么些套接字用来监听三个端口,当有叁个客商与服务器连接时,它接收这一个四个端口号,而那个时候这一个端口号正与那些套接字关联。当然客商不知底套接字这个细节,它只晓得四个地方和三个端口号。
addr:
  这是二个结果参数,它用来经受三个重临值,这重回值内定顾客端的地方,当然那些地点是透过有些地方构造来陈诉的,客户应该精晓这三个哪些的地址布局。假使对客商的地点不感兴趣,那么能够把那个值设置为NULL。
len:
  犹如大家所觉得的,它也是结果的参数,用来选用上述addr的构造的大小的,它指明addr构造所占用的字节个数。同样的,它也可以被安装为NULL。
万一accept成功再次来到,则服务器与客户已经不易树立连接了,那时候服务器通过accept重临的套接字来成功与顾客的通讯。

注意:

accept暗中同意会梗塞进度,直到有三个客商连接建立后回来,它回到的是一个新可用的套接字,这一个套接字是连接套接字。
当时大家要求区分三种套接字:
  监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器初叶调用socket(卡塔尔国函数生成的,称为监听socket描述字(监听套接字卡塔尔(قطر‎
  连接套接字:一个套接字会从积极连接的套接字化身为三个监听套接字;而accept函数重返的是已一而再再而三socket描述字(叁个连接套接字卡塔尔国,它表示着二个互联网已经存在的点点连接。
多少个服务器平日经常独有只创建叁个监听socket描述字,它在该服务器的生命周期内直接存在。内核为每一种由服务器进度选择的客户连接创立了多个已连接socket描述字,当服务器完毕了对有个别顾客的服务,相应的已一而再三番五次socket描述字就被关门。
  连接套接字socketfd_new 并从未假公济私新的端口与客商端通信,还是接收的是与监听套接字socketfd同样的端口号

1.2 Socket client顾客端建构

6State of Qatar      通信甘休以前,顾客端和服务器端都足以中断连接(任何一方都足以打电话)。

 对于各样程序系统都有一张单独的表。精确地讲,系统为种种运营的历程维护一张单 独的文书陈说符表。当进度展开一个文书时,系统把八个照准此文件之中数据布局的指针写入文件陈述符表,并把该表的索引值再次回到给调用者 。应用程序只需记住 这些描述符,并在之后操作该文件时接受它。操作系统把该描述符作为目录访谈进程描述符表,通过指针找到保存该文件全数的音讯的数据结构。

3.5、recv()/send()函数

自然也能够行使此外函数来得以完毕多少传送,比如read和write。

客商端建构步骤首要有:

TCP是依附连接的通讯左券,即先创立稳固连接后,再数据传输

本着套接字的系统数据构造:

3.5.1 send
 ssize_t send(int sockfd, const void *buf, size_t len, int flags);

随意是客商依然服务器应用程序都用send函数来向TCP连接的另一端发送数据。

客商程序平常用send函数向服务器发送诉求,而服务器则日常用send函数来向顾客程序发送应答。
  第叁个参数钦命发送端套接字描述符;
  第1个参数指明一(Wissu卡塔尔(NutrilonState of Qatar个寄存应用程序要发送数据的缓冲区;
  第多个参数指明实际要发送的数额的字节数;
  第几个参数日常置0。

  1. 伊始化IP地址和端口号;
  2. 生成socket实例,TCP/IP通讯选拔AF_INET(IPV4),SOCK_STREAM(流套接字类型,数据像字符流同样通过);
  3. connect(卡塔尔国函数进行IP和端口连接(对应的服务端会利用accept(State of Qatar函数生成八个通讯实例实行双边相互的通讯);
  4. 行使send(卡塔尔函数和recv(卡塔尔国函数起头通讯。

    1 # client 2 3 import socket 4 5 address = ('127.0.0.1', 31500) 6 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 # connect address to correct ip and port 8 s.connect(address)
    9 s.send(b'hello, I am client') 10 data = s.recv(1024).decode('utf-8') 11 print('the data received is', data) 12 13 s.close()

若是Socket通信基于UDP,则数据传输前无需接二连三,相同发短信或发电报,即便对方不在线,也得以发送数据,发送的数码在指如时期从没得到对方响应,则正是操作超时,能够筛选超时后再也发送数据。

   1)、套接字API里有个函数socket,它正是用来成立两个套接字。套接字设计的欧洲经济共同体思路是,单个系统调用就足以成立任何套接字,因为套接字是一定 笼统的。一旦套接字创立后,应用程序还亟需调用其余函数来内定具体细节。例如调用socket将开创七个新的描述符条款:

3.5.2 recv
  int recv( SOCKET s,  char FAR *buf, int len, int flags );   

无论是顾客依然服务器应用程序都用recv函数从TCP连接的另一端接纳数据。
 该函数的首先个参数钦命选用端套接字描述符;
 第二个参数指明一个缓冲区,该缓冲区用来存放在recv函数选拔到的数目;
 第二个参数指明buf的尺寸;
 第七个参数常常置0。

 

连带函数:

图片 2

3.6、close()函数

函数成效:
  在服务器与顾客端建构连接之后,会进展部分读写操作,达成了读写操作将在关闭相应的socket描述字,好比操作完展开的公文要调用fclose关闭张开的公文。
函数原型:

#include <unistd.h>
int close(int fd);

close三个TCP socket的缺省级银行为时把该socket标志为以关闭,然后立时回到到调用进度。该描述字不可能再由调用进度使用,也正是说无法再作为read或write的首先个参数。

注意:
close操作只是使相应socket描述字的引用计数-1,独有当引用计数为0的时候,才会触发TCP客商端向服务器发送终止连接要求。

2 socket的UDP通讯基本确立进度

1.socket()函数

   2)、就算套接字的内部数据布局包罗众多字段,可是系统创建套接字后,大许多字字段未有填写。应用程序创设套接字后在该套接字能够利用在此之前,必得调用别的的经过来填充那几个字段。

4、Linux下Socket编制程序实例

socket的UDP通信连接首要包含多少个部分,服务端与客户端

        socket(State of Qatar函数用于创制与钦点的劳务提供者绑定套接字,函数原型如下:

二、基本的socket接口函数

咱俩在Xshell5中,开启四个会话,分别用来运作socket_server端、socket_client端。

2.1 Socket server服务器组建

        socket=socket.socket(familly,type)

图片 3

4.1 编写socket_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//第一步:导入Socket编程的标准库
//这个标准库:linux数据类型(size_t、time_t等等)

#include <sys/types.h>
//提供socket函数以及数据结构
#include <sys/socket.h>

//数据解构(sockaddr_in)
#include <netinet/in.h>
//IP地址的转换函数
#include <arpa/inet.h>

//定义服务端
#define SERVER_PORT 9999


int main(){

 //第二步:创建socket
 //服务端的socket
 int server_socket_fd;
 //客户端
 int client_socket_fd;
 //服务端网络地址
 struct sockaddr_in  server_addr;
 //客户端网络地址
 struct sockaddr_in client_addr;

 //初始化网络地址
 //参数一:传变量的地址($server_addr)
 //参数二:开始为止 
 //参数三:大小
 //初始化服务端网络地址
 memset(&server_addr,0,sizeof(server_addr ));
 //初始化客户端网络地址
 //memset(&client_addr,0,sizeof(client_addr));

 //设置服务端网络地址-协议簇(sin_family)
 //AF_INET:TCP/IP协议、UDP
  //AF_ISO:ISO 协议         
 server_addr.sin_family = AF_INET;

 //设置服务端IP地址(自动获取系统默认的本机IP,自动分配)
 server_addr.sin_addr.s_addr = INADDR_ANY;

 //设置服务端端口
 server_addr.sin_port = htons(SERVER_PORT);

 //创建服务端socket 
 //参数一(family):通信域(例如:IPV4->PF_INET、IPV6等等......)
 //参数二(type):通信类型(例如:TCP->SOCK_STREAM,UDP->SOCK_DGRAM等等......)
 //参数三(protocol):指定使用的协议(一般情况下都是默认为0)
 //默认为0就是使用系统默认的协议,系统支持什么我就就用什么
 //TCP->IPPROTO_TCP
 //UDP->IPPROTO_UDP
 //SCTP->IPPROTO_SCTP
  server_socket_fd = socket(PF_INET,SOCK_STREAM,0);

  //判断是否创建成功
  if(server_socket_fd <0){
     printf("create error!");
     return 1;
  }


  printf("服务器创建成功!n");

  //服务端绑定地址
  //参数一:服务端socket
  //参数二:网络地址
  //参数三:数据类型大小
  //socketaddr和sockaddr_in
  bind(server_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));

  //监听客户端连接请求(服务端监听有没有客户端连接)
  //参数一:监听的服务器socket
  //参数二:客户端数量(未处理队列数量)
  listen(server_socket_fd,6);

  //接收客户端连接
  //参数一(sockfd):服务端
  //参数二(addr):客户端
  //参数三(addrlen):大小
 socklen_t sin_size = sizeof(struct sockaddr_in);
 //获取一个客户端
 client_socket_fd= accept(server_socket_fd,(struct sockaddr*)&client_socket_fd,&sin_size);
 //判断客户端是否连接成功
 if(client_socket_fd < 0){
     printf("连接失败");
     return 1;
 }
 //连接成功:读取客户端数据
 //BUFSIZ:默认值
 char buffer[BUFSIZ];
 int len=0;
 while(1){
     //参数一:读取客户端数据(数据源)
     //参数二:读取到哪里(我们要读取到缓冲区buffer)
     //参数三:每次读取多大BUFSIZ
     //参数四:从哪里开始读0

     len = recv(client_socket_fd,buffer,BUFSIZ,0);
     if(len > 0){
       //说明读取到了数据
       printf("%sn",buffer);

     }
 }
 //关闭服务端和客户端Socket
 //参数一:关闭的源
 //参数二:关闭的类型(设置权限)
 //SHUT_RD:关闭读(只允许写,不允许读)
 //SHUT_WR:关闭写(只允许读,不允许写)
 //SHUT_RDWR:读写都关闭(书写都不允许)
 shutdown(client_socket_fd,SHUT_RDWR);
 shutdown(server_socket_fd,SHUT_RDWR);


 printf("server end.....n");
 getchar();
 return 0;

}

服务器组建步骤首要有:

参数表明如下:

 

4.2 执行socket_server.c
root@jdu4e00u53f7:/usr/kpioneer/pthread# gcc -c socket_server.c
root@jdu4e00u53f7:/usr/kpioneer/pthread# gcc -o socket_server socket_server.o
root@jdu4e00u53f7:/usr/kpioneer/pthread# ./socket_server
服务器创建成功!
  1. 设置端口号,ip地址可以为空字符(‘’卡塔尔,即意味着选用任什么地方方来的数据报;
  2. 生成socket实例,UDP通讯选用AF_INET(IPV4),SOCK_DGRAM(数据报套接字类型,数据以数量报datagrams通过);
  3. bind(卡塔尔(قطر‎函数绑定IP和端口;
  4. 行使recvfrom(State of Qatar函数实行数量选拔,获得参数msg,addr,那七个参数分别为消息和顾客端的地点,可依据收到的addr进行通讯回复。

    1 import socket 2 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 3 sock.bind(('', 5656)) 4 print('server ready') 5 while True: 6 msg, addr = sock.recvfrom(1024) 7 print(msg, addr) 8 sock.sendto(b'hi, this is server', addr)

        familly,钦赐合同的地址宗族,可为AF_INET或AF_UNIX。AF_INET亲族满含Internet地址,AF_UNIX宗族用于同一台机械上的经过间通讯。

  服务器端先早先化/创立Socket,然后与端口绑定/绑定地址 (bind卡塔尔国,对端口实行监听(listen卡塔尔国,调用accept梗塞/等待延续,等待客商端连接。在那个时候候假设有个客商端最初化四个Socket,然后连 接服务器(connectState of Qatar,假设延续成功,那个时候客商端与服务器端的接连就确立了。客商端发送数据诉求,服务器端接收诉求并拍卖乞请,然后把应对数据发送 给客商端,客商端读取数据,最后关闭连接,一次交互作用甘休。

4.3 编写socket_client.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//第一步:导入Socket编程的标准库
//这个标准库:linux数据类型(size_t、time_t等等......)
#include<sys/types.h>
//提供socket函数及数据结构
#include<sys/socket.h>
//数据结构(sockaddr_in)
#include<netinet/in.h>
//ip地址的转换函数
#include<arpa/inet.h>

//定义服务器的端口号
#define SERVER_PORT 9999

int main(){

    //客户端socket
    int client_socket_fd;

    //服务端网络地址
    struct sockaddr_in  server_addr;
    //客户端网络地址
    struct sockaddr_in client_addr;

    //初始化网络地址
    //参数一:传变量的地址($server_addr)
    //参数二:开始位置 
    //参数三:大小
    //初始化服务端网络地址
     memset(&server_addr,0,sizeof(server_addr ));
    //AF_INET:TCP/IP协议、UDP
    //AF_ISO:ISO 协议         
     server_addr.sin_family = AF_INET;

    //设置服务端IP地址(自动获取系统默认的本机IP,自动分配)
    server_addr.sin_addr.s_addr = INADDR_ANY;

     //设置服务端端口
    server_addr.sin_port = htons(SERVER_PORT);

    //创建客户端
    client_socket_fd = socket(PF_INET,SOCK_STREAM,0);
    //判断是否创建成功
    if(client_socket_fd < 0){
       printf("create error!!!");
       return 1;
    }

    //连接服务器
    //参数一:哪一个客户端
    //参数二:连接服务器地址
    //参数三:地址大小
    int con_result = connect(client_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    if(con_result<0){
      printf("connect error!");
    return -1;
    }
     printf("create Socket Clientn ");

    //发送消息(向服务器发送内容)
    char buffer[BUFSIZ] = "Hello, Socket Server!";
    //参数一:指定客户端
    //参数二:指定缓冲区(冲那里数据读取)
    //参数三:实际读取的大小strlen(buffer)(其实读取到""结束)
    //参数四:从哪里开始读取
    send(client_socket_fd,buffer,strlen(buffer),0);

    //关闭
    shutdown(client_socket_fd,SHUT_RDWR);
    printf("client--- end-----n");

   return 0; 
}

2.2 Socket client顾客端创设

type,钦命套接字的品种。

2.1socket函数

4.4 执行socket_client.c
root@jdu4e00u53f7:/usr/kpioneer/pthread# gcc -o socket_client socket_client.o
root@jdu4e00u53f7:/usr/kpioneer/pthread# ./socket_client 
create Socket Client
 client--- end-----

顾客端建设布局步骤主要有:

套接字类型

说    明

SOCK_STREAM

提供顺序、可靠、双向和面向连接的字节流数据传输机制,使用TCP

SOCK_DGRAM

支持无连接的数据报,使用UDP

SOCK_RAW

原始套接字,可以用于接收本机网卡上的数据帧或者数据包

函数原型

4.5 再一次查看socket_server

小编们见到服务器创建成功! 下多了二个打印语句Hello, Socket Server! ,程序运转成功。

  1. 生成socket实例,UDP通讯接受AF_INET(IPV4),SOCK_STREAM(数据报套接字类型,数据以多少报datagrams通过);
  2. 无须连接直接利用sendto函数向目的ip和端口发送数据;
  3. 利用recvfrom(卡塔尔国函数选择服务端的数码。

    1 import socket 2 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 3 sock.sendto(b'hi, this is client.', ('localhost', 5656)) 4 data, msg = sock.recvfrom(1024) 5 print(data, msg)

2.bind()函数

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

5、Android下Socket编制程序实例(jni达成卡塔尔

 

bind(卡塔尔(قطر‎函数能够将本地地址与三个Socket绑定在同步,函数原型如下:

 

我们新建三个Java工程和二个Android工程,分别用来运营socket_server端、socket_client端。

3 socket的UDP广播式通讯基本确立进程

socket.bind( address )

 

5.1 Java工程端

3.1 Socket broadcast server服务端建构

参数address是二个双成分元组,格式是(host,portState of Qatar。host代表主机,port代表端口号。

返回值:

5.1.1 编写 SocketServer.java
package com.haocai;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {

    public static void main(String[] args) {
        try{
            ServerSocket serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress("192.168.90.221",9998));

            System.out.println("服务器Start...");
            while(true){
                //获取连接客户端
                Socket socket = serverSocket.accept();
                //读取内容
                new ReaderThread(socket).start();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    static class ReaderThread extends Thread{
        BufferedReader bufferedReader;
        public ReaderThread(Socket socket){
            try {
                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void run() {
            super.run();
            //循环读取内容
            String content = null;
            while(true){
                try {
                    while((content = bufferedReader.readLine())!=null){
                      System.out.println("接收到了客户端:"+content);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端创设步骤首要有:

3.listen()函数

  //再次来到sockfd     sockfd是描述符,相似于open函数。

5.1.2 运行SocketServer
服务器Start...
  1. 生成UDP的socket实例;
  2. 选取setsockopt设置socket的broadcast情势为True,地址复用(多少个套接字能够同期连接三个端口上State of Qatar;
  3. bind(卡塔尔国函数绑定IP和端口;
  4. 接收recvfrom(卡塔尔国函数进行数量选取,得到参数msg,addr,那八个参数分别为音讯和客户端的地点,可依照收到的addr实行通讯回复

    1 import socket 2 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 3 sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True) 4 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 5 sock.bind(('', 5656)) 6 print('server ready') 7 while True: 8 msg, addr = sock.recvfrom(1024) 9 print(msg, addr) 10 sock.sendto(b'hi, this is server', addr)

listen(State of Qatar函数能够将套接字设置为监听接入连接的景色,函数原型如下:

函数功效:

5.2 Android工程端

3.2 Socket broadcast client顾客端创设

listen(backlog);

  socket函数对应于普通文书的开拓操作。普通文书的开采操作重返三个文本 描述字,而socket(卡塔尔(قطر‎用于创设一个socket描述符(socket descriptor),它独一标记叁个socket。这几个socket描述字跟文件陈说字同样,后续的操作都有接收它,把它充任参数,通过它来开展部分 读写操作。

5.2.1 编写Java jni声明
package com.haocai.socketclient;

public class SocketUtil {
    public native void startClient(String serverIp,int serverPort);

    static {
        System.loadLibrary("socketlib");
    }

}

顾客端建设布局步骤首要有:

参数backlog钦赐等待连接队列的最大尺寸。

函数参数:

5.2.2 编写socket_client.c
#include"com_haocai_socketclient_SocketUtil.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//第一步:导入Socket编程的标准库
//这个标准库:linux数据类型(size_t、time_t等等......)
#include<sys/types.h>
//提供socket函数及数据结构
#include<sys/socket.h>
//数据结构(sockaddr_in)
#include<netinet/in.h>
//ip地址的转换函数
#include<arpa/inet.h>

#include <android/log.h>


#define  LOG_TAG    "socket_client"
#define  LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,FORMAT,##__VA_ARGS__);
#define  LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,FORMAT,##__VA_ARGS__);
#define  LOGD(FORMAT,...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,FORMAT, ##__VA_ARGS__);

JNIEXPORT void JNICALL Java_com_haocai_socketclient_SocketUtil_startClient
  (JNIEnv *env, jobject jobj, jstring server_ip_jstr, jint server_port){

    const char* server_ip = (*env)->GetStringUTFChars(env, server_ip_jstr, NULL);

    //客户端socket
    int client_socket_fd;

    //服务端网络地址
    struct sockaddr_in  server_addr;

    //初始化网络地址
    //参数一:传变量的地址($server_addr)
    //参数二:开始位置
    //参数三:大小
    //初始化服务端网络地址
     memset(&server_addr,0,sizeof(server_addr));
    //AF_INET:TCP/IP协议、UDP
    //AF_ISO:ISO 协议
     server_addr.sin_family = AF_INET;
    //设置服务端IP地址(自动获取系统默认的本机IP,自动分配)
     server_addr.sin_addr.s_addr = inet_addr(server_ip);

     //设置服务端端口
     server_addr.sin_port = htons(server_port);

    //创建客户端
    client_socket_fd = socket(PF_INET,SOCK_STREAM,0);
    //判断是否创建成功
    if(client_socket_fd < 0){

       LOGE("create error!");
       return ;
    }

    //连接服务器
    //参数一:哪一个客户端
    //参数二:连接服务器地址
    //参数三:地址大小
    int con_result = connect(client_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    if(con_result<0){
    LOGE("connect error!");

    return ;
    }

    //发送消息(向服务器发送内容)
    char buffer[BUFSIZ] = "Hello Socket Server!";
    //参数一:指定客户端
    //参数二:指定缓冲区(冲那里数据读取)
    //参数三:实际读取的大小strlen(buffer)(其实读取到""结束)
    //参数四:从哪里开始读取
    send(client_socket_fd,buffer,strlen(buffer),0);

    //关闭
    shutdown(client_socket_fd,SHUT_RDWR);
    LOGI("client--- end-----");
        (*env)->ReleaseStringUTFChars(env, server_ip_jstr, server_ip);
   return ;

  }
  1. 生成UDP的socket实例;
  2. 运用setsockopt设置socket的broadcast形式为True,地址复用(八个套接字能够何况连接三个端口上卡塔尔;
  3. 无须连接直接使用sendto函数以广播方式向<’broadcast’>和端口发送数据;
  4. 动用recvfrom(State of Qatar函数接纳服务端的数码。

    1 import socket 2 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 3 sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True) 4 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 5 for i in range(5): 6 sock.sendto(b'hi, this is client.', ('', 5656)) 7 data, msg = sock.recvfrom(1024) 8 print(data, msg)

4.accept()函数

  protofamily:即公约域,又称作家组织议族(family)。常用的合同族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、 AF_ROUTE等等。合同族决定了socket的地方类型,在通讯中必需运用对应的地址,如AF_INET决定了要用ipv4地址(三十几个人的)与端口号 (十三个人的)的组成、AF_UNIX决定了要用叁个万万路径名作为地点。

5.2.3 调用主程序MainActivity
package com.haocai.socketclient;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    public static final String SERVER_IP = "192.168.90.221";
    public static final int SERVER_PORT = 9998;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
    public void startSocket(View v){
        new Thread(new Runnable() {

            @Override
            public void run() {
                SocketUtil socketUtil = new SocketUtil();
                socketUtil.startClient(SERVER_IP,SERVER_PORT);
            }
        }).start();
    }
}

 

在劳动器端调用listen(卡塔尔函数监听接入连接后,能够调用accept(卡塔尔函数来等待接纳连接乞求。accept(卡塔尔国的函数原型如下:

     图片 4

5.3 再一次查看Java工程Log
接收到了客户端:Hello Socket Server!

4 socket的四十多线程通讯的创制进度

connection, address = socket.accept()

  type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。

源码下载

4.1 Socket thread server三十二线程服务端创建

调用accept(State of Qatar方法后,socket会跻身waiting状态。客商诉求连接时,accept(State of Qatar方法会创设连接并回到服务器。accept(卡塔尔方法重回叁个包涵四个因素的元组(connection,address卡塔尔国。第三个要素connection是新的socket对象,服务器必需通过它与客商通讯;第三个成分address是顾客的Internet地址。

     图片 5

Github:https://github.com/kpioneer123/SocketClient

八线程服务器的服务器创立与如今相近,独一差异之处在于accept函数重回新的通讯socket后调用线程模块运维二个新的子线程进行通讯。

5.recv()函数

  protocol:正是钦命左券。常用的合计有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们各自对应TCP传输合同、UDP传输左券、STCP传输合同、TIPC传输公约

非常谢谢:

guisu--Linux的SOCKET编制程序精解

此间补充创立了八个单线程的服务端,最终结出能够见见单线程的服务端需等待程序再一次循环至accept处技术继续下四个客商端的通信。

调用recv(卡塔尔国函数能够从已三番两次的Socket中选拔数据。recv(State of Qatar的函数原型如下:

  注意:却非地点的type和protocol能够自由组合的,如SOCK_STREAM不能够跟IPPROTO_UDP组合。当protocol为0时,会自行接受type类型对应的暗中同意左券。

 1 from socket import *
 2 from threading import Thread
 3 
 4 class Service():
 5     def __init__(self):
 6         #self.ip = '192.168.121.100'
 7         #self.port = 2049
 8         self.ip = '127.0.0.1'
 9         self.port = 31500
10         self.addr = (self.ip, self.port)
11         self.serv = socket(AF_INET, SOCK_STREAM)
12         self.serv.bind(self.addr)
13 
14         self.serv.listen(5)
15 
16     def run(self):
17         while True:
18             newServ, addr = self.serv.accept()
19             Thread(target=self.chat, args=(newServ, )).start()
20             
21     def chat(self, newServ):
22         i = 1
23         while i <= 10:
24             newServ.send('get data'.encode('utf-8'))
25             ra = newServ.recv(1024).decode('utf-8')
26             print(ra)
27             #newServ.close()
28             print('next')
29             i += 1
30 
31 class Servicex(Service):
32     def __init__(self):
33         Service.__init__(self)
34 
35     def run(self):
36         while True:
37             newServ, addr = self.serv.accept()
38             self.chat(newServ)
39 
40 #serv = Service()
41 #serv.run()
42 
43 serv = Servicex()
44 serv.run()

buf = sock.recv(size)

当大家调用socket创设二个socket时,重回的socket描述字它存在 于合同族(address family,AF_XXX)空间中,但尚无三个具体的地址。若是想要给它赋值一个地方,就非得调用bind(卡塔尔国函数,不然就当调用connect(State of Qatar、 listen(State of Qatar时系统会活动随机分配叁个端口

4.2 Socket thread client八十多线程顾客端建设布局

参数sock是选择数据的socket对象,参数size钦点选取数据的缓冲区的大大小小。recv(卡塔尔国的函数的归来选择的数额。

2.2bind()函数

三十二线程服务器的客商端创设与近来相通,分裂之处在于生成了八个socket的实例,并用线程模块同不经常间调用运营那四个socket通讯实例进行通讯。

6.send()函数

函数作用:

 1 import socket
 2 import time
 3 from threading import Thread
 4 
 5 class Chamber():
 6     def __init__(self, tag):
 7         #self.ip = '192.168.121.100'
 8         #self.port = 2049
 9         self.ip = '127.0.0.1'
10         self.port = 31500
11         self.tag = tag
12         self.addr = (self.ip, self.port)
13         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14         self.sock.connect(self.addr)
15 
16     def getTemper(self):
17         self.sock.send(('021?8E03'+self.tag).encode('utf-8'))
18         time.sleep(2)
19         print('Receive blocking', self.tag)
20         data = self.sock.recv(1024)
21         print(data)
22         #self.sock.close()
23 
24     def run(self):
25         for i in range(10):
26             self.getTemper()
27 
28 cham_1 = Chamber('C_1')
29 cham_2 = Chamber('C_2')
30 Thread(target=cham_1.run).start()
31 Thread(target=cham_2.run).start()

调用send(卡塔尔函数能够在已接连的Socket上发送数据。send(State of Qatar的函数原型如下:

  bind(State of Qatar函数把叁个地址族中的特定地方赋给socket,也得以说是绑定ip端口和socket。比方对应AF_INET、AF_INET6便是把八个ipv4或ipv6地址和端口号组合赋给socket。

 

sock.recv(buf)

函数原型:

参数sock是在已两次三番的Socket上发送数据。参数buf是也要已接连的Socket上发送数据。

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

7.close()函数

函数参数:

close (卡塔尔(قطر‎函数用于关闭叁个Socket,释放其所占领的具备能源。socket(卡塔尔(قطر‎的函数原型如下:

  1.函数的四个参数分别为:sockfd:即socket描述字,它是透过socket(卡塔尔函数成立了,独一标志八个socket。bind(State of Qatar函数正是将给那些描述字绑定贰个名字。

s.closesocket();

  2.addr:一个const struct sockaddr *指南针,指向要绑定给sockfd的商业事务地址。这一个地点构造事务所点创造socket时之处合同族的不等而各异,

参数s表示要关门的Socket。

  3.addrlen:对应的是地方的尺寸。

 connection.close()

通用函数类型:

运用socket通信的精练服务

struct sockaddr{
  sa_family_t  sa_family;
  char         sa_data[14];
}

如ipv4对应的是:

import socket 

import sys 

# 创建 socket 对象 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

# 获取本地主机名 

host = socket.gethostname()
port = 9999  

# 绑定端口号 s.bind((host, port)) 

# 设置最大连接数,超过后排队 

s.listen(5) 

# 等待客户端连接 

while True:
    conn, addr = s.accept() # 建立客户端连接  

  print("连接地址: %s" % str(addr))
    msg = '|------成功连接服务端!------|'  

 conn.send(msg.encode('utf-8'))

    conn.close() # 关闭连接

图片 6

应用socket通信的简易客户端

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order 2字节*/
    struct in_addr sin_addr;   /* internet address 4字节*/
  unsigned char sin_zero[8];
};
/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};
import socket 

图片 7

import sys

ipv6对应的是: 

 创建 socket 对象 


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

图片 8

# 获取本地主机名

struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};
struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ 
};
host = socket.gethostname() 

# 设置端口号 

port = 9999  

# 连接服务,指定主机和端口 

s.connect((host, port)) 

# 接收小于 1024 字节的数据  

msg = s.recv(1024)
s.close() print (msg.decode('utf-8'))

图片 9

Unix域对应的是: 

前后相继写完事后先要运维服务端,在运行客性格很顽强在暗礁险滩或巨大压力面前不屈端,假若是两台微管理机之间的测验,客服端的ip地址须要更动。

#define UNIX_PATH_MAX    108
struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */ 
    char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};

运行结果:

  通平常衣服务器在开行的时候都会绑定一个斐然的地址(如ip地址+端口号),用于提供劳务,客户即可通过它来三番若干遍服务器;而客商端就毫无内定,有系统自动分配贰个端口号和本人的ip地址组合。那正是怎么通平常服装务器端在listen从前会调用bind(State of Qatar,而客商端就不会调用,而是在connect(卡塔尔(قطر‎时由系统随机生成一个。

                    |------成功连接服务端!------|

2.2.1地址转变

int_addr_t indet_addr(const char *cp)

  作用:将字符串情势的IP地址转变为整数型的IP地址(网络字节序)

   范例:int_addr.saddr=inet_addr("192.168.1.1");

char *inet_ntoa(struct in_addr)

   功效:将整数方式的IP地址转变为字符串模式的IP地址

2.2.2网络字节序

  互连网字节序定义:收到的率先个字节被看做高位看待,那将必要发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的率先个字节是该数字在内部存款和储蓄器中开局部址对应的字节。可以知道多字节数值在出殡和安葬前,在内存中数值应该以多方法贮存。 
  互联网字节序说是大端字节序。

  小端法(Little-Endian卡塔尔正是低位字节排泄在内部存储器的洼地址端即该值的前奏地址,高位字节排泄在内部存款和储蓄器的高地址端。 
  大端法(Big-Endian卡塔尔国就是高位字节排放在内部存款和储蓄器的洼地址端即该值的起头地址,低位字节排泄在内部存款和储蓄器的高地址端。

网络字节序转变:---->无论是数额恐怕地方只要当先多个字节就不得不调换

图片 10

 uint32_t htonl(uint32_t hostlong);
  将32位的数据从主机字节序转换为网络字节序
  in_addr.saddr = htonl(INADDR_ANY)

  uint16_t htons(uint16_t hostshort);
  将16位的数据从主机字节序转换为网络字节序

  uint32_t ntohl(uint32_t netlong);
  将32位的数据从网络字节序转换为主机字节序

  uint16_t ntohs(uint16_t netshort);
  将16位的数据从网络字节序转换为主机字节序

图片 11

2.3、listen()、connect()函数

  假诺作为多少个服务器,在调用socket(卡塔尔、bind(卡塔尔国之后就能够调用listen(卡塔尔国来监听这几个socket,假若客户端此时调用connect(卡塔尔国发出连接央浼,服务器端就能够抽出到这些央求。

 int listen(int sockfd, int backlog);
  int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)

  listen函数的首先个参数即为要监听的socket描述字,第一个参数为相应socket可以排队的最亚松森接个数。socket(卡塔尔函数制造的socket暗许是二个能动类型的,listen函数将socket变为被动类型的,等待客商的连年乞请。

  connect函数的率先个参数即为客商端的socket描述字,第二参数为服务器的socket地址,第多个参数为socket地址的长度。客商端通过调用connect函数来树立与TCP服务器的接连。成功再次回到0,若一而再再而三失败则赶回-1。

2.4、accept()函数

  TCP服务器端依次调用socket(卡塔尔(قطر‎、bind(卡塔尔、listen(卡塔尔(قطر‎之后,就能够监听内定的socket地址了。TCP顾客端依次调用socket(State of Qatar、connect(State of Qatar之后就向TCP服务器发送了叁个三番五次央浼。TCP服务器监听到那个诉求之后,就能够调用accept(卡塔尔函数取接受央浼,那样总是就创立好了。之后就能够起来互连网I/O操作了,几天前常于平日文书的读写I/O操作。

  int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接connect_fd

参数sockfd

  参数sockfd正是地方表明中的监听套接字,那么些套接字用来监听三个端口,当有三个顾客与服务器连接时,它使用这一个一个端口号,而那时那些端口号正与那么些套接字关联。当然顾客不明了套接字那些细节,它只精通二个地点和八个端口号。
参数addr
  那是一个结果参数,它用来经受二个重临值,那返回值钦定客商端的地点,当然那几个地点是经过有个别地点布局来呈报的,客商应该了解那三个什么之处结构。假诺对顾客的地点不感兴趣,那么可以把那些值设置为NULL。
参数len

犹如咱们所认为的,它也是结果的参数,用来经受上述addr的构造的高低的,它指明addr构造所占领的字节个数。相仿的,它也得以棉被服装置为NULL。 

假若accept成功重临,则服务器与客商已经正确树立连接了,那时候服务器通过accept重临的套接字来形成与客商的通讯。

注意:

  accept暗许会窒碍进度,直到有贰个客户连接创设后赶回,它回到的是叁个新可用的套接字,这几个套接字是连接套接字。

那时候大家必要区分二种套接字,

  监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器开端调用socket(卡塔尔国函数生成的,称为监听socket描述字(监听套接字卡塔尔国

    连接套接字:一个套接字会从积极连接的套接字化身为二个监听套接字;而accept函数重临的是已连接socket描述字(三个连接套接字卡塔尔,它意味着着一个网络已经存在的点点连接。

  一个服务器平常日常独有只开创贰个监听socket描述字,它在该服务器的生命周期内直接存在。内核为种种由服务器进度选用的客商连接创立了叁个已连接socket描述字,当服务器达成了对某些客商的服务,相应的已一而再socket描述字就被关闭。

  连接套接字socketfd_new 并未据为己有新的端口与客户端通讯,照旧接受的是与监听套接字socketfd同样的端口号

2.5、recv()/send()函数

  当然也足以应用此外函数来促成数量传送,比如read和write。

2.5.1send函数

 ssize_t send(int sockfd, const void *buf, size_t len, int flags);

  无论是客商依旧服务器应用程序都用send函数来向TCP连接的另一端发送数据。

  客户程序通常用send函数向服务器发送诉求,而服务器则平时用send函数来向客商程序发送应答。

  该函数的首先个参数钦赐发送端套接字描述符;

  第贰个参数指爱他美个置放应用程序要发送数据的缓冲区;

  第多个参数指明实际要发送的数码的字节数;

  第三个参数常常置0。

  这里只描述同步Socket的send函数的实行流程。当调用该函数时,send先比较待发送数据的尺寸len和套接字s的出殡和安葬缓冲的 长度,假如len大于s的发送缓冲区的长短,该函数重临SOCKET_ECRUISERROEnclave;假设len小于大概等于s的发送缓冲区的尺寸,那么send先反省公约是还是不是正在发送s的发送缓冲中的数据,要是是就等候公约把数量发送完,如若协商还尚未起来发送s的发送缓冲中的数据依然s的发送缓冲中未有数量,那么 send就相比较s的发送缓冲区的剩下空间和len,假设len大于剩余空间大小send就平素等候公约把s的出殡缓冲中的数据发送完,假诺len小于剩余空间大小send就可是把buf中的数据copy到剩余空间里(注意而不是send把s的出殡缓冲中的数据传到连接的另一端的,而是左券传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。如若send函数copy数据成功,就回到实际copy的字节数,借使send在copy数据时现身谬误,那么send就重临SOCKET_E奥迪Q3ROENCORE;若是send在伺机合同传送数据时互连网断开的话,那么send函数也回到SOCKET_ERROR。

  要静心send函数把buf中的数据成功copy到s的发送缓冲的多余空间里后它就回来了,不过那个时候那几个多少并不一定登时被传到三回九转的另一端。假若左券在一而再一连的传递进程中现身互联网错误的话,那么下多少个Socket函数就能够回来SOCKET_E大切诺基ROSportage。(每贰个除send外的Socket函数在施行的最开端总要先等待套接字的出殡缓冲中的数据被合同传送达成才能持续,如若在等待时现身互联网错误,那么该Socket函数就重临SOCKET_ERROR)

2.5.2recv函数学习

int recv( SOCKET s,     char FAR *buf,      int len,     int flags     );   

 不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

 该函数的第一个参数指定接收端套接字描述符;

 第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

 第三个参数指明buf的长度;

 第四个参数一般置0。

  这里只描述同步Socket的recv函数的举办流程。当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被左券传送完成,即便公约在传送s的出殡缓冲中的数据时现身互连网错误,那么recv函数重临SOCKET_E奥迪Q3ROENCORE,若是s的出殡和下葬缓冲中一向不数据只怕数额被左券成功发送完成后,recv先检查套接字s的接纳缓冲区,若是s选拔缓冲区中从相当的少少或然左券正在选拔数据,那么recv就一直等待,只到协商把数量选用完结。当左券把多少选择完结,recv函数就把s的收受缓冲中的数据copy到buf中(注意协议接纳到的数据只怕大于buf的尺寸,所以 在此种情景下要调用四回recv函数能力把s的选用缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接受数据是切磋来成功的),recv函数再次回到其实际copy的字节数。借使recv在copy时出错,那么它回到SOCKET_E路虎极光RO本田CR-V;假若recv函数在守候公约采纳数据时网络中断了,那么它重返0。

2.6、close()函数

  在服务器与顾客端建构连接之后,会开展局地读写操作,完结了读写操作将要关闭相应的socket描述字,好比操作完张开的文件要调用fclose关闭张开的文书。

#include <unistd.h>
int close(int fd);

  close多少个TCP socket的缺省级银行为时把该socket标识为以关闭,然后马上回到到调用进度。该描述字不可能再由调用进度使用,相当于说无法再作为read或write的首先个参数。

本文由10bet手机官网发布于web前端,转载请注明出处:Python的网络编程,模型理解

上一篇:程序中加入自定义声音,VC中如何加入背景音乐 下一篇:没有了
猜你喜欢
热门排行
精彩图文