原文出处: Andrew_liu
python的网络变成比c语言简单许多, 封装许多底层的实现细节, 方便程序员使用的同时, 也使程序员比较难了解一些底层的东西, 我觉得学网络编程还是用c语言更好一点.
写这篇博文, 也希望回顾并整理一下以前学过的c语言和linux下一些东西, 会将一些Linux网络编程的函数和Python网络变成函数做一个简单的对照, 方便记忆
Socket(翻译为套接字, 我觉得很挫),是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。它是网络进程的ID。网络通信,归根到底还是进程间的通信(不同计算机上的进程间通信, 又称进程间通信, IP协议进行的主要是端到端通信)。在网络中,每一个节点(计算机或路由)都有一个网络地址,也就是IP地址。两个进程通信时,首先要确定各自所在的网络节点的网络地址。但是,网络地址只能确定进程所在的计算机,而一台计算机上很可能同时运行着多个进程,所以仅凭网络地址还不能确定到底是和网络中的哪一个进程进行通信,因此套接口中还需要包括其他的信息,也就是端口号(PORT)。在一台计算机中,一个端口号一次只能分配给一个进程,也就是说,在一台计算机中,端口号和进程之间是一一对应关系。
所以,使用端口号和网络地址的组合可以唯一的确定整个网络中的一个网络进程.
端口号的范围从0~65535,一类是由互联网指派名字和号码公司ICANN负责分配给一些常用的应用程序固定使用的“周知的端口”,其值一般为0~1023, 用户自定义端口号一般大于等于1024, 我比较喜欢用8888
每一个socket都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的
1.1. Socket类型
socket类型在Liunx和Python是一样的, 只是Python中的类型都定义在socket模块中, 调用方式socket.SOCK_XXXX
- 流式socket(SOCK_STREAM) 用于TCP通信
流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性
- 数据报socket(SOCK_DGRAM) 用于UDP通信
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP
- 原始socket(SOCK_RAW) 用于新的网络协议实现的测试等
原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以, 其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
2. Socket编程
2.1. TCP通信
TCP通信的基本步骤如下:
服务端:socket—bind—listen—while(True){—accept—recv—send—-}—close
客户端:socket———————————-connect—send—recv——-close
socket函数
使用给定的地址族、套接字类型、协议编号(默认为0)来创建套接字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#Linux
;
IPv6网络协议
SOCK_DGRAM
0.
1。
#python
)
.
.
0或者默认
error异常
|
2.1.1. 服务器端函数
bind函数
将套接字绑定到地址, python下,以元组(host,port)的形式表示地址, Linux下使用sockaddr_in结构体指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#Linux
;
)的返回值
结构体指针变量
#####
/常用的结构体
{
AF_INET
port编号
IP地址
/未使用
;
in_addr
{
;
;
####
;
1
#python
)
)返回的套接字对象
port)
为一个字符串
为整型
|
listen函数
使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求。如果客户端有连接请求,端口就会接受这个连接
1
2
3
4
5
6
7
8
9
10
|
#Linux
;
.
128
1
#python
)
)返回的套接字对象
5就可以了
|
accept函数
接受远程计算机的连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。
1
2
3
4
5
6
7
8
9
10
11
|
#Linux
;
.
bind的结构体是同种类型的,系统会把远程主机的信息(远程主机的地址和端口号信息)保存到这个指针所指的结构体中。
表示结构体的长度,为整型指针
1
#python
)
)返回的套接字对象
address是连接客户端的地址
|
2.1.2. 客户端函数
connect函数
用来请求连接远程服务器
1
2
3
4
5
6
7
8
9
10
11
|
#Linux
;
.
IP与端口号信息
表示结构体变量的长度
1
#python
)
)返回的套接字对象
error错误
|
2.1.3. 通用函数
接收远端主机传来的数据
recv函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#Linux
;
.也就是新的套接字。
表示缓冲区
表示缓冲区的长度
0
1
#python
)
)返回的套接字对象
指定要接收的数据大小
提供有关消息的其他信息,通常可以忽略
返回值为数据以字符串形式
|
send函数
发送数据给指定的远端主机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#Linux
;
.
一般为常量字符串
表示长度
0
1
#python
)
)返回的套接字对象
要发送的字符串数据
提供有关消息的其他信息,通常可以忽略
string的字节大小。
)
#完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。
None,失败则抛出异常。
|
close函数
关闭套接字
1
2
3
4
5
6
7
8
|
#Linux
;
sockfd
1
#python
)
)返回的套接字对象
|
2.2. 简单的客户端服务器TCP连接
一个简单的回显服务器和客户端模型, 客户端发出的数据, 服务器会回显到客户端的终端上(只是一个简单的模型, 没考虑错误处理等问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#服务器端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#socket模块
#执行系统命令模块
#设置缓冲区大小
#IP和端口构成表示地址
#生成一个新的socket对象
#设置地址复用
#绑定地址
#监听, 最大监听数为5
:
#接收TCP连接, 并返回新的套接字和地址
client_addr
:
#从客户端接收数据
data
#发送数据到客户端
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#客户端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
sys
socket
#设置缓冲区的大小
#IP和端口构成表示地址
:
#返回新的socket对象
:
]
)
#要连接的服务器地址
:
:
continue
#发送数据到服务器
#从服务器端接收数据
data
)
|
2.2.1. 带错误处理的客户端服务器TCP连接
在进行网络编程时, 最好使用大量的错误处理, 能够尽量的发现错误, 也能够使代码显得更加严谨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#服务器端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
sys
#socket模块
#设置缓冲区大小
#IP和端口构成表示地址
:
#生成一个新的socket对象
:
]
)
#设置地址复用
:
#绑定地址
:
]
)
#监听, 最大监听数为5
:
#接收TCP连接, 并返回新的套接字和地址, 阻塞函数
client_addr
:
#从客户端接收数据
data
#发送数据到客户端
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#客户端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
sys
socket
#设置缓冲区的大小
#IP和端口构成表示地址
:
#返回新的socket对象
:
]
)
#要连接的服务器地址
:
:
continue
#发送数据到服务器
#从服务器端接收数据
data
)
|
2.3. UDP通信
UDP通信流程图如下:
服务端:socket—bind—recvfrom—sendto—close
客户端:socket———-sendto—recvfrom—close
sendto()函数
发送UDP数据, 将数据发送到套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #Linux ; . 一般为常量字符串 表示长度 0 表示地址的结构体 ) 1。 #Python ) )返回的套接字对象 port)的元组 提供有关消息的其他信息,通常可以忽略 发送的字节数。 |
recvfrom()函数
接受UDP套接字的数据, 与recv()类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#Linux
;
.
一般为常量字符串
表示长度
0
IP地址及端口号
)。
errno。
#Python
)
address是发送数据的套接字地址
指定要接收的数据大小
提供有关消息的其他信息,通常可以忽略
|
2.4. 简单的客户端服务器UDP连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#服务器端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
socket
#设置缓冲区大小
#IP和端口构成表示地址
#生成新的套接字对象
#套接字绑定IP和端口
:
#从客户端接收数据
data
#发送数据给客户端
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#客户端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
socket
struct
#设置缓冲区
#IP和端口构成表示地址
#生成新的套接字对象
:
)
#向服务器发送数据
#从服务器接收数据
data
)
|
2.5. 其他
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
)
#返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
)
#返回套接字自己的地址。通常是一个元组(ipaddr,port)
)
#设置给定套接字选项的值。
)
#返回套接字选项的值。
)
#设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
)
#返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
)
#返回套接字的文件描述符。
)
#如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
)
#创建一个与该套接字相关连的文件
|
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 爬虫 (三) – Socket 网络编程 - Python技术站