TCP编程

Client

创建一个基于TCP连接的Socket:

# coding: utf-8
import socket # 创建一个TCP连接:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立连接:
s.connect(('52fhy.com', 80)) # 发送HTTP请求
s.send(b'GET / HTTP/1.1\r\nHost: 52fhy.com\r\nConnection: close\r\n\r\n') # 读取响应
buffer = []
while True:
d = s.recv(1024)
if d:
buffer.append(d)
else:
break data = b''.join(buffer) # 关闭连接
s.close() # 解析响应
header, body = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8')) with open('52fhy.html', 'wb') as f:
f.write(body)

输出:

HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Sat, 11 Feb 2017 08:16:43 GMT
Content-Type: text/html
Content-Length: 8368
Last-Modified: Mon, 19 Sep 2016 07:04:02 GMT
Connection: close
Vary: Accept-Encoding
ETag: "57df8de2-20b0"
Accept-Ranges: bytes

代码说明:

1、创建socket连接的时候使用AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6SOCK_STREAM指定使用面向流的TCP协议。

2、建立连接的connect()接受一个tuple,包含地址和端口号。

3、发送请求是模拟浏览器发送一个Request,实际浏览器请求时包含更多项:

GET / HTTP/1.1
Host: 52fhy.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

换行使用\r\n\r\n\r\n则表示该段内容的结束,用于分隔请求的header和请求的body。

4、读取远程服务器响应则使用recv()每次接受1024byte内容。注意接收的是字节内容,不是字符串,所以拼接以b开头。

5、读取响应完毕,关闭socket连接。

6、通过\r\n\r\n可以区分响应头和返回的body内容(即网页),这里将网页内容保存到了文件里。

Server

上节例子说明了如何编写客户端,这节讲如何创建一个基于TCP的Server端。

和客户端编程相比,服务器编程就要复杂一些。

服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Socket连接了。

# coding: utf-8
import socket, threading # 创建一个TCP连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口
s.bind(('127.0.0.1', 9999)) # 开始监听客户端连接
# 传入的参数指定等待连接的最大数量
s.listen(3) # 输出提示语
print('Server is running on %s:%s' % ('127.0.0.1', 9999))
print('Waiting for connection...') def tcp_link(sock, addr):
print('Accept new connection from %s:%s...' % addr) # 参数addr是一个tuple
sock.send(b'Welcome!') # 发送问候语给客户端 while True:
r = sock.recv(1024)
if not r or r.decode('utf-8') == 'exit': # 结束连接指令
break # 输出客户端发来的信息,注意元组拼接
msg = addr + (r.decode('utf-8'),)
print('%s:%s : %s' % msg) # 回复客户端
sock.send( ('you say: %s' % r.decode('utf-8') ).encode('utf-8') )
sock.close()
print('Client %s:%s is closed.' % addr) while True:
# 接受一个新连接:
sock, addr = s.accept()
print(addr) # ('127.0.0.1', 62090) # 创建新线程来处理TCP连接:
# 每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接
t = threading.Thread(target=tcp_link, args=(sock, addr))
t.start()

还需要个客户端发送消息:

# coding: utf-8
import socket # 创建一个TCP连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接服务端
s.connect(('127.0.0.1', 9999)) # 接收来自服务端的信息
print(s.recv(1024).decode('utf-8')) # 发送数据给服务端
for x in [b'Python', b'PHP']:
s.send(x)
print(s.recv(1024).decode('utf-8')) # 发送断开连接命令
s.send(b'exit') s.close()

先运行服务端:

erver is running on 127.0.0.1:9999
Waiting for connection...

这时候运行一个客户端:

Welcome!
you say: Python
you say: PHP

服务端输出:

('127.0.0.1', 62428)
Accept new connection from 127.0.0.1:62428...
127.0.0.1:62428 : Python
127.0.0.1:62428 : PHP
Client 127.0.0.1:62428 is closed.

编写代码需要注意:

1、服务端和客户端互相发送和接收到的是字节Bytes,需要使用encode()或者decode()转码;

2、服务端使用accept()接收到的是一个元组,例如:('127.0.0.1', 62090);

3、服务端必须使用多线程以处理来自多个客户端的连接;

4、服务端同一个端口,被一个Socket绑定了以后,就不能被别的Socket绑定了。

用TCP协议进行Socket编程在Python中十分简单。对于客户端,要主动连接服务器的IP和指定端口;对于服务器,要首先监听指定端口,然后,对每一个新的连接,创建一个线程或进程来处理。通常,服务器程序会无限运行下去。

UDP编程

TCP建立的是可靠的连接,而使用UDP,无需建立连接,只要知道对方的IP和端口,就可以发送数据。

UDP是一个非连接的协议,传输数据之前源端和终端不建立连接。UDP使用尽最大努力交付,即不保证可靠交付。

使用UDP虽然传输数据不可靠,但比TCP要快。

user_udp_server.py:

# coding: utf-8
import socket # 建立UDP连接:SOCK_DGRAM表示UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定地址和端口,之后无需监听
s.bind(('127.0.0.1', 9999)) print('UDP server is running on %s:%s' % ('127.0.0.1', 9999)) while True:
# recvfrom()返回客户端发过来的数据及地址端口信息
data, addr = s.recvfrom(1024)
msg = addr + (data.decode('utf-8'),)
print('Received from %s:%s : %s' % msg) # 使用sendto()发送消息,注意第二个参数是addr
s.sendto(('you say : %s ' % data.decode('utf-8')).encode('utf-8') , addr)

user_udp_client.py

# coding: utf-8
import socket # 建立UDP连接:SOCK_DGRAM表示UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 服务端地址
serv_addr = ('127.0.0.1', 9999) #无需使用connect()连接 # 发送数据给服务端
for x in [b'Python', b'PHP']:
s.sendto(x, serv_addr)
print(s.recv(1024).decode('utf-8')) # s.close()

先运行服务端:

UDP server is running on 127.0.0.1:9999

再运行客户端:

you say : Python
you say : PHP

服务端输出:

Received from 127.0.0.1:57827 : Python
Received from 127.0.0.1:57827 : PHP

与TCP不同的是:

1、服务端和客户端建立连接时选择UDP:SOCK_DGRAM

2、服务端无需进行监听listen()

3、服务端使用recvfrom()返回客户端发过来的数据及地址端口信息,而不是recv()或者accept()

4、服务端和客户端使用sendto()发送数据,第二个参数必填,是addr元组;

5、客户端创建连接后无需使用connect()连接服务端;

这里服务端我们没有使用多线程,因为比较简单。需要注意的是客户端发送数据如果加入一句s.close(),本次连接关闭,服务端也会退出。

UDP的使用与TCP类似,但是不需要建立连接。此外,服务器绑定UDP端口和TCP端口互不冲突,也就是说,UDP的9999端口与TCP的9999端口可以各自绑定。

Python学习--19 网络编程的更多相关文章

  1. python学习(20) 网络编程

    原文链接:http://www.limerence2017.com/2018/01/02/python20/ python 网络编程和基本的C语言编程一样,效率不是很高,如果为了封装通信库建议采用C/ ...

  2. python学习之网络编程基础

    引入场景:客户与银行关系 银行职员负责给客户提供取钱服务,客户通过账户密码跟银行职员建立合作关系.此时银行职员就可以作为服务器,当用户A取完钱后他需要等待下一个用户的接入,用户的账号密码就是建立合作关 ...

  3. python学习(九) 网络编程学习--简易网站服务器

    python `网络编程`和其他语言都是一样的,服务器这块步骤为:`1. 创建套接字``2. 绑定地址``3. 监听该描述符的所有请求``4. 有新的请求到了调用accept处理请求` Python ...

  4. Python学习之==>网络编程

    一.什么是网络编程 使用Python进行网络编程,就是通过Python打开一个网站,或者请求一个http接口.可以通过标准模块urllib实现,也可以通过更简单易用的第三方模块requests实现. ...

  5. python学习总结---网络编程

    网络编程 相关概念 - OSI七层模型:它从低到高分别是:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. - TCP/IP: 在OSI七层模型基础上简化抽象出来的一套网络协议簇,现在得到 ...

  6. Python学习day36-并发编程(2)

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

  7. 第六篇:python高级之网络编程

    python高级之网络编程   python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及 ...

  8. Python学习之==>面向对象编程(二)

    一.类的特殊成员 我们在Python学习之==>面向对象编程(一)中已经介绍过了构造方法和析构方法,构造方法是在实例化时自动执行的方法,而析构方法是在实例被销毁的时候被执行,Python类成员中 ...

  9. Python学习day40-并发编程(终)

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

随机推荐

  1. 分治算法(Divide-and-Conquer)和Google的云计算

    1.云计算:涉及到存储.计算.资源的调度和权限的管理等   2.分治算法的原理:           讲一个复杂的问题,分成若干个简单的子问题进行解决,然后对子问题的记过进行合并,得到原有问题的解   ...

  2. Extjs的架构设计思考,单页面应用 or 多页面?

    写在前面:不要认为 EXTJS 高版本就是一个界面改良,在项目中,仍然用 N 张页面,在 N 张页面部署 EXTJS .这种方式不用多讲,效率问题大家都看得出来, EXTJS 是一个集成开发工具,注定 ...

  3. Codeforces Round 212 Div 2 报告(以前没写完,现在也没心情补了,先就这样吧)

    A. Two Semiknights Meet 题目大意:有一个8x8的棋盘,上面放有两个骑士,骑士以“田字”的方式走.每个方格都被定义为good或者bad,问骑士能否在good的格子中相遇? 由于骑 ...

  4. Ubuntu14.04下搭建VPN服务

    直接上步骤: 1.第一步需要安装PPTP,以用来提供VPN服务. sudo apt-get install pptpd 如果有问题的话比如提示找不到之类的,apt-get update 一下应该就可以 ...

  5. 【Xilinx-Petalinux学习】-01-开发环境搭建与PetaLinux的安装

    开发环境 VMware12, Ubuntu 16.04 64 bit 在VMware中安装Ubuntu,用户名:xilinx-arm 密码:root step1: VMware Tools问题 不知道 ...

  6. fold change(ratio)

    fold change 英文简称 : FC 中文全称 : 倍性变化 所属分类 : 生物科学 词条简介 : 一种用于描述两个用于相比的对象数量差异的方法.例如,第一个样本和第二个样本的量是50/10,那 ...

  7. mySQL内存及虚拟内存优化设置

    为了装mysql环境测试,装上后发现启动后mysql占用了很大的虚拟内存,达8百多兆.网上搜索了一下,得到高人指点my.ini.再也没见再详细的了..只好打开my.ini逐行的啃,虽然英文差了点,不过 ...

  8. 关于自己封装Web前端框架的思考和探索

    一.引言 首先这些年关于前端技术层出不穷,从最早的只用js做简单验证,到现在发现好像大前端已经无所不能了的感觉.特别是为了降低前端开发复杂度,涌现了一大批 的MVC/MVVM模式的前端框架,不停了刷新 ...

  9. Java div 使用说明

    1. 置于底部 position:absolute; bottom:0;

  10. js验证IP及子网掩码的合法性

    function checkIP(ip) {     obj=ip;    var exp=/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0 ...