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. Perl 使用perl命令批量替换文件内容

    对linux系统下面多个文本文件内容做处理,是SA经常需要完成的工作.如何高效的完成这个工作,perl应该是一个不错的语言工具.你甚至不需要编写perl脚本,用命令就可以完成上面的工作. perl 命 ...

  2. spring学习-ApplicationContext-spring上下文深入理解

    4月份开始复习一遍spring相关知识.让自己巩固一下spring大法的深奥益处,所以就看了大佬的博客,转载留下来日后继续研读.认为重点的标记为红色 以下文章内容转载自:http://www.cnbl ...

  3. INSERT,UPDATE,DELETE时不写日志

    我们在维护数据库的过程中,可能会遇到海量数据的存储和维护,但在有的情况下,需要先试验,然后再对实际的数据进行操作,那么在试验这个过程中,我们是不需要写日志的,因为当你对海量数据操作时,产生的日志可能会 ...

  4. docker-compose可持续集成之nexus

    什么是 Nexus 概述 Nexus 是一个强大的仓库管理器,极大地简化了内部仓库的维护和外部仓库的访问. 2016 年 4 月 6 日 Nexus 3.0 版本发布,相较 2.x 版本有了很大的改变 ...

  5. springboot swagger2注解使用

    swagger2 注解整体说明 @Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI ...

  6. IO流——字节流

    文件输出流 FileOutputStream:文件输出流是用于将数据写入 File,每次运行,都会覆盖之前文件中的数据 FileOutputStream(File file):创建一个向指定 File ...

  7. build gradle dependencies闭包的详解

    转 :https://blog.csdn.net/guanguanboy/article/details/91043641 dependencies闭包的整体功能是指定当前项目所有依赖关系:本地依赖. ...

  8. [转帖]深度剖析一站式分布式事务方案 Seata-Server

    深度剖析一站式分布式事务方案 Seata-Server https://www.jianshu.com/p/940e2cfab67e 金融级分布式架构关注 22019.04.10 16:59:14字数 ...

  9. Mysql 数据库 表中列的操作

    [1]Mysql数据库中表的列操作 Mysql中关于表中列的操作集语句: -- [1]增加一列 ) DEFAULT NULL COMMENT '目的码区号'; -- [2]增加一列,在dnis_are ...

  10. Matlab的solve()函数的使用方法

    Matlab的solve()函数的使用方法 1.首先是对方程的求解 不废话直接上例子 syms x: eq=x^2+2*x+1; s=solve(eq,x); 结果如下 完美的算出了方程的解 现在对上 ...