Socket网络编程-TCP编程

                                   作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.socket介绍

1>.TCP/IP协议

2>.跨网络的主机间通讯

  在建立通信连接的每一端,进程间的传输要有两个标志:

  IP地址和端口号,合称为套接字地址 socket address

  客户机套接字地址定义了一个唯一的客户进程

  服务器套接字地址定义了一个唯一的服务器进程

3>.什么是socket套接字

  套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

  Socket:套接字,进程间通信IPC的一种实现,允许位于不同主机(或同一主机)上不同进程之间进行通信和数据交换,SocketAPI出现于1983年,4.2 BSD实现。

  Socket API:封装了内核中所提供的socket通信相关的系统调用。

  Python中提供了socket标准库,非常底层的接口库。

4>.协议族(Socket Domain)

AF表示Address Family,用于socket()第一个参数
  AF_INET:
    对应IPV4
  AF_INET6
    对应IPV6
  AF_UNIX
    同一主机不同进程之间通信时使用,对应Unix Domain Socket,windows没有。

5>.socket Type(根据使用的传输层协议)

SOCK_STREAM
  可靠的传递,面向连接的流套接字。默认值,TCP协议。
SOCK_DGRAM
  不可靠的传递,无连接的数据报文套接字。UDP协议。
SOCK_RAW:
  裸套接字,无须tcp或udp,APP直接通过IP包通信

6>.C/S编程

  Socket编程,需要两端,一般来说需要一个服务端、一个客户端,服务端称为Server,客户端称为Client。 这种编程模式也称为C/S编程。

  套接字相关的系统调用:
    socket(): 创建一个套接字
    bind(): 绑定IP和端口
    listen(): 监听
    accept(): 接收请求
    connect(): 请求连接建立
    write(): 发送
    read(): 接收
    close(): 关闭连接

7>.python中的socket常用方法

  socket.recv(bufsize[, flags])
    获取数据。默认是阻塞的方式

  socket.recvfrom(bufsize[, flags])
    获取数据,返回一个二元组(bytes, address)

  socket.recv_into(buffer[, nbytes[, flags]])
    获取到nbytes的数据后,存储到buffer中。如果 nbytes没有指定或0,将buffer大小的数据存入buffer中。返回接收的字节数。

  socket.recvfrom_into(buffer[, nbytes[, flags]])
    获取数据,返回一个二元组(bytes, address)到buffer中

  socket.send(bytes[, flags])
    TCP发送数据

  socket.sendall(bytes[, flags])
    TCP发送全部数据,成功返回None

  socket.sendto(string[,flag],address)
    UDP发送数据

  socket.sendfile(file, offset=0, count=None)
    python 3.5版本开始,发送一个文件直到EOF,使用高性能的os.sendfile机制,返回发送的字节数。如果win下不支持sendfile, 或者不是普通文件,使用send()发送文件。offset告诉 起始位置。   socket.getpeername()
    返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)

  socket.getsockname()
    返回套接字自己的地址。通常是一个元组(ipaddr,port)

  socket.setblocking(flag)
    如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值),非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常

  socket.settimeout(value)
    设置套接字操作的超时期,timeout是一个浮点数,单位是 秒。值为None表示没有超时期。一般,超时期应该在刚创 建套接字时设置,因为它们可能用于连接的操作(如 connect())

  socket.setsockopt(level,optname,value)
    设置套接字选项的值。比如缓冲区大小。太多了,去看文档。不同系统,不同版本都不尽相同   socket.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None)
    创建一个与该套接字相关连的文件对象,将recv方法看做读方法,将send方法看做写方法。

二.TCP服务端编程

1>.服务器端编程步骤

  创建Socket对象 

  绑定IP地址Address和端口Port。bind()方法
    IPv4地址为一个二元组('IP地址字符串', Port) 开始监听,将在指定的IP的端口上监听。listen()方法   获取用于传送数据的Socket对象
    socket.accept() -> (socket object, address info)
      accept方法阻塞等待客户端建立连接,返回一个新的Socket对象和客户端地址的二元组 地址是远程客户端的地址,IPv4中它是一个二元组(clientaddr, port)
      接收数据
        recv(bufsize[, flags]) 使用缓冲区接收数据
      发送数据
        send(bytes)发送数据   Server端开发
    socket对象 --> bind((IP, PORT)) --> listen --> accept --> close
     |--> recv or send --> close

2>.实战案例写一个群聊程序的服务端ChatServer

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import socket
import threading
import datetime logging.basicConfig(level=logging.INFO, format="%(asctime)s %(thread)d %(message)s") """
注意,这个代码为实验用,代码中瑕疵还有很多。Socket太底层了,实际开发中很少使用这么底层的接 口。
"""
class ChatServer:
def __init__(self,ip="127.0.0.1",port=6666):
self.conn = socket.socket() #创建socket对象
self.addr = (ip,port)
self.clients = {} #存放客户端连接容器
self.event = threading.Event() #判断服务是否启动
self.lock = threading.Lock() #为了线程安全而引入的 def start(self): #启动服务,会监听IP地址和端口哟~
self.conn.bind(self.addr) #将IP地址和端口绑定到套接字上
self.conn.listen() #监听绑定的套接字 #accept会阻塞主线程,所以开一个新线程
threading.Thread(target=self.accept).start() def accept(self): #处理客户端的链接
while not self.event.is_set():
conn,client = self.conn.accept() #该方法默认会进入阻塞状态
f = conn.makefile("rw") #将socket封装成一个文件对象来操作,支持读写
with self.lock:
self.clients[client] = f,conn #如果有新链接就添加到客户端字典 #准备接收数据,recv是阻塞的,开启新的线程
threading.Thread(target=self.recv,args=(f,client)).start() def recv(self,f,client): #处理客户端数据
print("in recv")
while not self.event.is_set():
try:
data = f.readline()
print(data)
except Exception as e:
logging.error(e)
data = "quit" msg = data.strip()
print(msg, "++++++++++++++++++") #和客户端约定退出命令
if msg == "quit" or msg == "": #主动端口得到空串
with self.lock:
_,conn = self.clients.pop(client)
f.close()
conn.close()
logging.info("{} quit ...".format(client))
break msg = "{:%Y/%m/%d %H:%M:%S} ip:port => {}:{}\n data => {}\n".format(datetime.datetime.now(),*client, data)
logging.info(msg) with self.lock:
for f1,_ in self.clients.values():
f1.write(msg)
f1.flush() def stop(self): #停止服务
self.event.set()
with self.lock:
for f,s in self.clients.values():
f.close()
s.close()
self.conn.close() def main():
server = ChatServer()
server.start() while True:
cmd = input(">>> ").strip()
if cmd == "quit":
server.stop()
threading.Event.wait(3) #关闭服务需要等待时间
break
logging.info(threading.enumerate()) #用来观察断开后线程的变化
logging.info(server.clients) if __name__ == '__main__':
main()

三.TCP客户端编程

1>.客户端编程步骤

  创建Socket对象 

  连接到远端服务端的ip和port,connect()方法 

  传输数据  
    使用send、recv方法发送、接收数据   关闭连接,释放资源

2>.实战案例写一个群聊程序的客户端ChatClient

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import socket
import threading
import datetime
import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) """
同样,这样的客户端还是有些问题的,仅用于测试。
"""
class ChatClient:
def __init__(self, ip='127.0.0.1', port=6666):
self.sock = socket.socket()
self.addr = (ip, port)
self.event = threading.Event() def start(self): # 启动对远端服务器的连接
self.sock.connect(self.addr)
self.send("I'm ready.")
# 准备接收数据,recv是阻塞的,开启新的线程
threading.Thread(target=self.recv, name="recv").start() def recv(self): # 接收服务端的数据
while not self.event.is_set():
try:
data = self.sock.recv(1024) # 阻塞
except Exception as e:
logging.error(e)
break msg = "{:%Y/%m/%d %H:%M:%S} ip:port => {}:{}\n data => {}\n".format(datetime.datetime.now(),*self.addr, data.strip())
logging.info(msg) def send(self, msg:str):
data = "{}\n".format(msg.strip()).encode() # 服务端需要一个换行符
self.sock.send(data) def stop(self):
self.sock.close()
self.event.wait(3)
self.event.set()
logging.info('Client stops...') def main():
client = ChatClient()
client.start()
while True:
cmd = input('>>>')
if cmd.strip() == 'quit':
client.stop()
break
client.send(cmd) # 发送消息 if __name__ == '__main__':
main()

Socket网络编程-TCP编程的更多相关文章

  1. python网络编程--socket,网络协议,TCP

    一. 客户端/服务端架构(用到网络通信的地方) 我们使用qq.微信和别人聊天,通过浏览器来浏览页面.看京东的网站,通过优酷.快播(此处只是怀念一下)看片片啥的等等,通过无线打印机来打印一个word文档 ...

  2. 36 - 网络编程-TCP编程

    目录 1 概述 2 TCP/IP协议基础 3 TCP编程 3.1 通信流程 3.2 构建服务端 3.3 构建客户端 3.4 常用方法 3.4.1 makefile方法 3.5 socket交互 3.4 ...

  3. 五十四、linux 编程——TCP 编程模型

    54.1 编程模型介绍 54.1.1 TCP 客户端服务器编程模型 客户端调用序列 调用 socket 函数创建套接字 调用 connect 连接服务器端 调用 I/O 函数(read/write) ...

  4. 五十四 网络编程 TCP编程

    Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 客户端 大多数连接都是可靠 ...

  5. [Python 网络编程] TCP编程/群聊服务端 (二)

    群聊服务端 需求分析: 1. 群聊服务端需支持启动和停止(清理资源); 2. 可以接收客户端的连接; 接收客户端发来的数据 3. 可以将每条信息分发到所有客户端 1) 先搭架子: #TCP Serve ...

  6. 五十三、linux 编程——TCP 编程基本介绍

    53.1 socket 套接字 53.1.1 介绍 Socket(套接字)是一种通讯机制,它包含一整套的调用接口和数据结构的定义,它给应用进程提供了使用如 TCP/UDP 灯网络协议进行网络通讯的手段 ...

  7. 63 网络编程(四)——TCP编程

    TCP编程 TCP编程是面向连接的数据传输,所以需要时用IO流来建立连接. 用户输出流到服务器,服务器输入流接收数据. 服务器输出流到用户,用户输入流接收. 基本流程 服务器端 创建服务器端:Serv ...

  8. 基于网络编程 TCP协议 及 socket 基本语法

    socket是什么 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面, ...

  9. Socket网络编程(TCP/IP/端口/类)和实例

    Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次 ...

随机推荐

  1. 只访问tomcat,不访问项目时,显示指定内容。

      1.情景展示 我们知道,将javaWeb项目部署到tomcat后,访问该项目的url路径构成是: 网路协议+"://"+ip地址+":"+tomcat设定的 ...

  2. 京东联盟开发(6)——推广链接解析SKUID

    1.从推广方案中分析出价格及推广码 $keyword = " [京东]长虹(CHANGHONG) L3 老人手机 移动/联通2G 老年机 双卡双待 咖啡 原价:168.00元 券后价:163 ...

  3. 【07月02日】A股滚动市盈率PE最低排名

    ​仅根据最新的市盈率计算公式进行排名,无法对未来的业绩做出预测. 方大集团(SZ000055) - 滚动市盈率PE:2.68 - 滚动市净率PB:1.2 - 滚动年化股息收益率:3.78% - 建筑产 ...

  4. 【计算机视觉】ImageNet介绍

    ImageNet介绍 ImageNet 是一个计算机视觉系统识别项目, 是目前世界上图像识别最大的数据库.是美国斯坦福的计算机科学家,模拟人类的识别系统建立的.能够从图片识别物体.ImageNet是一 ...

  5. Python学习教程(十)精选 TOP45 值得学习的Python项目

    精选 TOP45 值得学习的Python项目 [导读]热门资源博客 Mybridge AI 比较了 18000 个关于 Python 的项目,并从中精选出 45 个最具竞争力的项目.我们进行了翻译,在 ...

  6. Springboot Actuator之十二:actuator aop

    前言spring 中aop是一个核心概念,spring boot 是如何实现自动化配置的?现在我们就来分析一下 解析spring boot 中自动化配置是读取/META-INF/spring.fact ...

  7. C++完全二叉树的权值

    #include<stdio.h> #include<stdlib.h> #include<math.h> #include<string.h> int ...

  8. BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并

    传送门--BZOJCH 考虑两种情况: 1.答案由一个最长公共子串+可能的一个模糊匹配位置组成.这个用SAM求一下最长公共子串,但是需要注意只出现在\(S\)的开头和\(T\)的结尾的子串是不能够通过 ...

  9. Java学习:接口(interface)的使用于注意事项

    接口 接口就是一种公共的规范标准.只要符合规范标准,就可以大家通用. 接口就是多个类的公共规范.接口是一种引用数据类型,最重要的内容就是其中的:抽象方法. 如何定义一个接口的格式 如何定义一个接口的格 ...

  10. 6、VUE指令

    1.指令的格式 1.1. 指令的概念 指令是指带有v-前缀的特殊属性,指令的职责是当其表达式的值改变时,相应的将某些行为应用到DOM上. 1.2. 指令必须是html的属性 指令只能以带前缀的html ...