socket()模块和套接字对象的内建方法
一、socket()模块函数
要使用socket.socket()函数来创建套接字,其语法如下:
socket(socket_family,socket_type,protocol=0)
如上所述,scoket_family不是AF_UNIX就是AF_INET,scoket_type可以是SOCK_STREAM或SOCK_DGRAM,protocol一般不填,默认值为0.
创建一个TCP/IP套接字,你要这样调用socket.socket():
tcpsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
同样的,创建一个UDP/IP的套接字,你要这样:
udpsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
由于socket有太多属性,我们一般使用from import socket * 语句,将所有属性导入命名空间。
二、套接字对象内建方法
下面是一些套接字对象常用的方法。
函数 | 描述 |
s.bind() | 绑定地址(主机名、端口号对)到套接字 |
s.listen() | 开始TCP监听 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
函数 | 描述 |
s.connect() | 主动初始化TCP服务器连接 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
函数 | 描述 |
s.recv() | 接受TCP数据 |
s.send() | 发送TCP数据 |
s.sendall() | 完整发送TCP数据 |
s.recvfrom() | 接受UDP数据 |
s.sendto() | 发送UDP数据 |
s.getpeername() | 连接到当前套接字的远端地址(TCP连接) |
s.getsockname() | 当前套接字的地址 |
s.getsockopt() | 返回指定套接字的参数 |
s.setsockopt() | 设定指定套接字的参数 |
s.close() | 关闭套接字 |
函数 | 描述 |
s.settimeout() | 设置阻塞套接字操作的超时时间 |
s.gettimeout() | 得到阻塞套接字操作的超时时间 |
s.setblocking() | 设置套接字的阻塞与非阻塞模式 |
函数 | 描述 |
s.fileno() | 套接字的文件描述符 |
s.makefile() | 创建一个与该套接字关联的文件对象 |
提示:在运行网络应用程序时,最好在不同的电脑上执行服务器和客户端的程序。
三、创建TCP服务器和TCP客户端
根据上面的介绍,现在我们应该能创建一个完整的通信模型了。下面是理论上的伪代码:
1.套接字理论模型
先来创建一个TCP服务器
#创建一个TCP服务器
ss = socket() #创建服务器套接字
ss.bind() #把地址绑定到套接字上
ss.listen() #监听连接
inf_loop: #服务器无线循环
cone,addr = ss.accept() #接收客户端连接
comm_loop: #通信循环
cone.recv()/cs.send() #对话(接受与发送)
cone.close() #关闭客户端套接字
ss.close() #关闭服务器套接字(可选)
所有的套接字都用socket.socket()函数来创建。服务器需要“坐在某个端口上”等待请求。所以它们必须要绑定到一个本地的地址上。
由于TCP是一个面向连接的通信系统,在TCP服务器可以开始工作之前,要先完成一些设置。
TCP服务器必须监听(进来的)连接,设置完成之后,服务器就可以进入无线循环了。
一个简单的(单线程的)服务器会调用accept()函数等待连接的到来,
默认情况下,accept()函数是阻塞式的,即程序在连接到来之前会处于挂起状态。套接字也支持非阻塞模式。
一旦接收到一个连接,accept·()函数就会返回一个单独的客户端套接字用于后续的通信。
使用新的客户端套接字就像把客户的电话转给一个客户服务人员。当一个客户打电话进来的时候,总机接了电话,然后把电话转到合适的人那里来处理客户的需求。
这样就可以空出主机,也就是最初的那个服务器套接字。
当客户端连接关闭后,服务器继续等待下一个客户端的连接。代码的最后一行会把服务器套接字关闭,由于是无限循环也许用不到。
再来创建一个TCP客户端
#创建一个TCP客户端
ss = socket() #创建一个客户端套接字
ss.connect() #尝试连接服务器
comm_loop: #通信循环
cs.send()/cs.recv() #对话(接受或发送)
cs.close() #关闭客户端套接字
在客户端有了套接字之后,马上就可以调用connect()函数去连接服务器。连接建立之后,就可以与服务器开始对话了,对话结束后,客户端就可以关闭套接字,结束连接
2.建立一个单一的连接
#服务器端
from socket import *
cs = socket(AF_INET,SOCK_STREAM)
cs.bind(('127.0.0.1',8888))
cs.listen(5) print("Wait for......")
anne,addr = cs.accept()
print(anne)
print(addr)
anne.close()
#客户端
from socket import *
cl = socket(AF_INET,SOCK_STREAM)
cl.connect(("127.0.0.1",8888))
cl.send("Hello,world".encode("utf-8"))
cl.close()
先启动服务器:
Wait for...... #accept处于等待状态
然后执行客户端,看服务器端的变化:
<socket.socket fd=384, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8888), raddr=('127.0.0.1', 54883)>
('127.0.0.1', 54883) #客户端IP地址和端口号
上面的的代码有点单一,有多个客户端同时访问该如何?这就该用到后面的多线程,稍后会讲,这里有另外的折中代码,可以一直访问,虽然一次只能访问一个。
#服务器端
from socket import *
cs = socket(AF_INET,SOCK_STREAM)
cs.bind(("127.0.0.1",8888))
cs.listen(5)
print("Have Listen") while True:
cone,addr = cs.accept()
while True:
data = cone.recv(1024)
if len(data) == 0:break #如果收到TCP消息,则关闭客户端套接字
print(data.decode("utf-8"))
cone.send(data.upper())
cone.close()
cs.close() #客户端
from socket import *
cs = socket(AF_INET,SOCK_STREAM)
cs.connect(("127.0.0.1",8888))
while True:
ssg = input(">>>").strip()
if not ssg:continue #避免空格造成的停顿
cs.send(ssg.encode("utf-8")) #发
data = cs.recv(1024)
print(data.decode("utf-8")) #收
cs .close()
下面是在linux下的版本测试:
#服务端
#!/usr/bin/env python
#coding:utf-8 from socket import *
import time HOST = '192.168.43.131'
PORT = 8808
BUFSIZ = 1024
ADDR = (HOST,PORT) tcpser = socket(AF_INET,SOCK_STREAM)
tcpser.bind(ADDR)
tcpser.listen(5) while True:
print "等待连接......"
anne,addr = tcpser.accept()
print "...连接:",addr
while True:
data = anne.recv(BUFSIZ)
if not data:
break
anne.send('[%s] %s' % (time.strftime('%c'),data))
anne.close()
tcpser.close() #客户端
#!/usr/bin/env python from socket import * HOST = '192.168.43.131'
PORT = 8088
BUFSIZ = 1024
ADDR = (HOST,PORT) tcpcli = socket(AF_INET,SOCK_STREAM)
tcpcli.connect(ADDR) while True:
data = input(">>>")
if not data:
continue
tcpcli.send(data.encode("utf-8"))
data = tcpcli.recv(BUFSIZ)
if not data:
break
print(data.decode("utf-8"))
tcpcli.close()
四、创建UDP服务器和UDP客户端
由于UDP服务器不是面向连接的,所以不用像TCP服务器那样做那么多设置工作。
创建一个UDP服务器
#创建UDP服务器
ss = socket() #创建一个服务器套接字
ss.bind() #绑定服务器套接字
inf_loop: #服务器无限循环
cs = ss.recvfrom()/ss.sendto() #对话(接收与发送)
ss.close() #关闭服务器套接字
从伪代码中可以看出,使用的还是那套先创建套接字然后绑定到本地地址(主机/端口)的方法,无限循环中包含了从客户接受消息。
创建一个TCP服务器
#创建一个UDP服务器
cs = socket() #创建客户端套接字
comm_loop: #通讯循环
cs.sendto()/cs.recvfrom() #对话(发送/接收)
cs.close() #关闭客户端套接字
创建一个真实的案例:
#创建一个服务器
from socket import * HOST = "127.0.0.1"
PORT = 8989
BUFSIZ = 1024
ADDR = (HOST,PORT) udpser = socket(AF_INET,SOCK_DGRAM)
udpser.bind(ADDR) while True:
print("等待请求......")
conn,addr = udpser.recvfrom(BUFSIZ) #接收到的消息无需转交
udpser.sendto( conn.upper(),addr) #需要的话返回一个结果就可以了
print("...来自",addr) udpser.close()
UDP和TCP服务器的另一个重要的区别是,由于数据报套接字是无连接的,所以无法把客户端连接交给另外的套接字进行后续的通讯。
这些服务器只是接收消息,需要的话,给客户端返回一个结果就可以了。
#创建一个客户端服务器
from socket import * HOST = "127.0.0.1"
PORT = 8989
BUFSIZ = 1024
ADDR = (HOST,PORT) udpcli = socket(AF_INET,SOCK_DGRAM) while True:
data = input(">>>")
if not data:
break
udpcli.sendto(data.encode("utf-8"),ADDR)
data,ADDR = udpcli.recvfrom(BUFSIZ)
if not data:
continue
print(data.decode("utf-8")) udpcli.close()
UDP客户端的循环基本上与TCP客户端的完全一样。唯一的区别就是,我们不用先去跟UDP服务器建立连接,而是直接把消息发送出去,然后等待服务器的回复。
还可以,创建多个客户端,UDP不同于TCP需要建立连接。
#服务端
from socket import *
server = socket(AF_INET,SOCK_DGRAM)
server.bind(('127.0.0.1',9100))
while True:
conn,addr = server.recvfrom(1024)
print("访问来自%s,端口号是:%s" % (addr[0],addr[1]))
server.sendto(conn.upper(),addr) #返回消息的时候,必须指定端口号和ip #客户端1
from socket import *
client = socket(AF_INET,SOCK_DGRAM)
while True:
data = input(">>>") #发送空格也行,不会报错,一次发送,也不会占用资源
client.sendto(data.encode("utf-8"),('127.0.0.1',9100))
conn,addr = client.recvfrom(1024)
print(conn.decode('utf-8')) #客户端2
from socket import *
client = socket(AF_INET,SOCK_DGRAM)
while True:
data = input(">>>")
client.sendto(data.encode("utf-8"),('127.0.0.1',9100))
conn,addr = client.recvfrom(1024)
print(conn.decode('utf-8'))
执行结果:
访问来自127.0.0.1,端口号是:60715
访问来自127.0.0.1,端口号是:60716
小结:
总的来说,UDP和TCP服务的流程相同,有两点:UDP无需提前连接直接发送消息,UDP服务器无法把客户端的连接转交出去。
socket()模块和套接字对象的内建方法的更多相关文章
- socket模块(套接字模块)
socket模块(套接字模块) 一.最简单版本(互传一次就结束) # 客户端 import socket client = socket.socket() client.connect(('127.0 ...
- Python套接字编程(1)——socket模块与套接字编程
在Python网络编程系列,我们主要学习以下内容: 1. socket模块与基本套接字编程 2. socket模块的其他网络编程功能 3. SocketServer模块与简单并发服务器 4. 异步编程 ...
- 类装饰器,元类,垃圾回收GC,内建属性、内建方法,集合,functools模块,常见模块
'''''''''类装饰器'''class Test(): def __init__(self,func): print('---初始化---') print('func name is %s'%fu ...
- 查看Python的版本、内建方法和模块等内容的方法
若想更好地应用Python帮助我们解决日常生活的问题,就必须了解清楚它的内建方法和模块等特性.相信不少同学在安装某个版本的Python后,对于内建方法之类都是一知半解,希望本文能帮助了解Python的 ...
- 【Socket编程】【第一节】【Socket基本原理和套接字】
参考http://c.biancheng.net/view/2351.html 一.scoket套接字(告诉你使用哪种数据传输方式) 这个世界上有很多种套接字(socket),比如 DARPA Int ...
- 使用socket()函数创建套接字
在Linux中,一切都是文件,除了文本文件.源文件.二进制文件等,一个硬件设备也可以被映射为一个虚拟的文件,称为设备文件.例如,stdin 称为标准输入文件,它对应的硬件设备一般是键盘,stdout ...
- 【Socket规划】套接字Windows台C语言
[编译环境]:Visual Studio 2013 这是服务端实现流程. #include<stdio.h> #include<stdlib.h> #include<wi ...
- Raw Socket(原始套接字)实现Sniffer(嗅探)
参考资料: https://www.xuebuyuan.com/3190946.html https://blog.csdn.net/zxygww/article/details/52093308 i ...
- 【Socket】linux套接字技术之tcp
1.mystery引入 1)UDP也可以编写出C/S程序 ,另外TCP也可以编写点对点通信. 2)网络的本质就是资源共享,当前流行的P2P应用正好暗合了这种精神. 3)当前流 ...
随机推荐
- js将用户上传gif动图分解成多张帧图片
js将用户上传gif动图分解成多张帧图片 写在前面 工作中遇到一个这么一个需求:这是一个多图上传的场景,如果用户上传选择多张图片,则上传后直接展示多张图片,如果上传的图片是gif动图,则需要分解这张动 ...
- spring security 3.1 实现权限控制
spring security 3.1 实现权限控制 简单介绍:spring security 实现的权限控制,能够分别保护后台方法的管理,url连接訪问的控制,以及页面元素的权限控制等, secur ...
- App打包上架流程(iOS转)
由于苹果的机制,在非越狱机器上安装应用必须通过官方的Appstore, 开发者开发好应用后上传Appstore,也需要通过审核等环节. AppCan作为一个跨主流平台的一个开发平台,也对ipa包上传A ...
- 如何设置esxi的网卡与网络
很多朋友安装了vmware esxi后,不懂得服务器上的网卡该如何设置以及如何使用,我们在这里来介绍一下vmware esxi的网卡设置 工具/原料 一台服务器,配有两块千兆网卡 在服务器安装好v ...
- python之函数enumerate()
enumerate函数可以遍历列表 for i in range(len(a)): print a[i] 等价于: for index,item in enumerate(a): print inde ...
- 【转】 在Eclipse中使用JUnit4进行单元测试(中级篇)
http://blog.csdn.net/andycpp/article/details/1327346 我们继续对初级篇中的例子进行分析.初级篇中我们使用Eclipse自动生成了一个测试框架,在这篇 ...
- Hibernate每个层次类一张表(使用注释)
在上一文章中,我们使用xml文件将继承层次映射到一个表. 在这里,我们将使用注释来执行同样的任务.需要使用@Inheritance(strategy = InheritanceType.SINGLE_ ...
- CentOS下使用MyTop实时监控MySQL
CentOS下使用MyTop实时监控MySQL MyTop的项目页面为:http://jeremy.zawodny.com/mysql/mytop/ MyTop安装 $ yum -y install ...
- 不通过AppStore,在iOS设备上直接安装应用程序的原理
本文转载至 http://mobile.51cto.com/hot-439095.htm 通过itms-services协议,可以通过safari浏览器直接在iOS设备上安装应用程序.利用这种方式, ...
- C++基础题
刚在网上转看到几道对于巩固基础很有帮助的C++基础题,反正闲着也是闲着,就做了下,具体题型如下: 答案是我自己写,不一定对,如果有朋友看到不对的,欢迎指正,万分感谢! 1. 一个指针类型的对象占用内存 ...