一、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()模块和套接字对象的内建方法的更多相关文章

  1. socket模块(套接字模块)

    socket模块(套接字模块) 一.最简单版本(互传一次就结束) # 客户端 import socket client = socket.socket() client.connect(('127.0 ...

  2. Python套接字编程(1)——socket模块与套接字编程

    在Python网络编程系列,我们主要学习以下内容: 1. socket模块与基本套接字编程 2. socket模块的其他网络编程功能 3. SocketServer模块与简单并发服务器 4. 异步编程 ...

  3. 类装饰器,元类,垃圾回收GC,内建属性、内建方法,集合,functools模块,常见模块

    '''''''''类装饰器'''class Test(): def __init__(self,func): print('---初始化---') print('func name is %s'%fu ...

  4. 查看Python的版本、内建方法和模块等内容的方法

    若想更好地应用Python帮助我们解决日常生活的问题,就必须了解清楚它的内建方法和模块等特性.相信不少同学在安装某个版本的Python后,对于内建方法之类都是一知半解,希望本文能帮助了解Python的 ...

  5. 【Socket编程】【第一节】【Socket基本原理和套接字】

    参考http://c.biancheng.net/view/2351.html 一.scoket套接字(告诉你使用哪种数据传输方式) 这个世界上有很多种套接字(socket),比如 DARPA Int ...

  6. 使用socket()函数创建套接字

    在Linux中,一切都是文件,除了文本文件.源文件.二进制文件等,一个硬件设备也可以被映射为一个虚拟的文件,称为设备文件.例如,stdin 称为标准输入文件,它对应的硬件设备一般是键盘,stdout ...

  7. 【Socket规划】套接字Windows台C语言

    [编译环境]:Visual Studio 2013 这是服务端实现流程. #include<stdio.h> #include<stdlib.h> #include<wi ...

  8. Raw Socket(原始套接字)实现Sniffer(嗅探)

    参考资料: https://www.xuebuyuan.com/3190946.html https://blog.csdn.net/zxygww/article/details/52093308 i ...

  9. 【Socket】linux套接字技术之tcp

      1.mystery引入      1)UDP也可以编写出C/S程序 ,另外TCP也可以编写点对点通信.    2)网络的本质就是资源共享,当前流行的P2P应用正好暗合了这种精神.    3)当前流 ...

随机推荐

  1. 基于Away3D实现全景的相机控制器。

    最近研究打算做个全景的Demo,发现Away3D本身的天空盒跟全景属于两种完全不同东西.最后只能基于HoverController来扩展(原因是HoverController能提供的距离控制,类似拉近 ...

  2. CentOS设置sendmail发件人,让sendmail不显示通过XXX代发

    0.有一个十分快速的方法 命令:hostname itzhanzhang.com,但是重启后会失效,于是请接着往下看一劳永逸的方法: 1.设置你的主机名 默认的主机名是类似于“VM_24_76_cen ...

  3. virtualenv下使用matplotlib

    Unable to “import matplotlib.pyplot as plt” in virtualenv   (PyMVPA) SimilarFacedeMacBook-Pro:PyMVPA ...

  4. vue 事件处理器

    事件处理器 1.监听事件 可以用v-on指令监听DOM事件来触发一些js代码. 2.方法事件处理器 许多事件处理的逻辑都很复杂,所以直接把js代码写在v-on指令中是不可行的.因此v-on可以接受一个 ...

  5. SQLServer -- 竟然默认不区分大小写

    SELECT * FROM USER_INFO WHERE USERNAME = :username; 这样的写法,:username的值竟然不区分大小写 原因:数据库的排序规则设置的是Chinese ...

  6. hdu 1078 FatMouse and Cheese【dp】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 题意:每次仅仅能走 横着或竖着的 1~k 个格子.求最多能吃到的奶酪. 代码: #include ...

  7. Javadoc生成html帮助文档

    注意事项: 右键项目 -> Export -> Java -> JavaDoc -> 选定Public表示录入所有的源文件,其他的可想而知    按步骤走下去最后Finish时 ...

  8. [Unity3D]Unity3D游戏开发之伤害数值显示

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.众所周知,在RPG游戏策划中最为重要的一个环节是数值策划.数值策划是一个关于游戏平衡方面的概念 ...

  9. python 线程(thread)

    #coding:utf-8#多线程#Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装 #绝大数情况下 ...

  10. FileToolkit 文件工具箱

    import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.*; import org.apache ...