基于TCP协议的socket套接字编程

基于TCP协议的socket套接字编程

一、什么是Socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

[

  • 注意:也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序,而程序的pid是同一台机器上不同进程或者线程的标识。

二、套接字发展史及分类

2.1 基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

2.2 基于网络类型的套接字家族

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

三、套接字工作流程

[

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束,使用以下Python代码实现:

import socket

# socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0
socket.socket(socket_family, socket_type, protocal=0)

# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能大幅减短我们的代码
tcpSock = socket(AF_INET, SOCK_STREAM)

3.1 服务端套接字函数

方法 用途
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

3.2 客户端套接字函数

方法 用途
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

3.3公共用途的套接字函数

方法 用途
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

3.4面向锁的套接字方法

方法 用途
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

3.5面向文件的套接字的函数

方法 用途
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

四、基于TCP协议的套接字编程

4.1服务器

import socket

#1、买手机
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM
# print(phone)

#2、插入/绑定手机卡
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8081))

#3、开机
phone.listen(5)  # 半连接池,限制的是请求数

#4、等待电话连接
print('start....')
conn, client_addr = phone.accept()  #(三次握手建立的双向连接,(客户端的ip,端口))
print(conn)
print(client_addr)

#5、通信:收\发消息
data = conn.recv(1024)  #最大接收的字节数
print('来自客户端的数据', data)
conn.send(data.upper())

# import time
# time.sleep(500)
#6、挂掉电话连接
conn.close()

#7、关机
phone.close()

4.2 客户端

import socket
# socket.AF
#1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(phone)
#2、拨电话
phone.connect(('127.0.0.1', 8081))  # 指定服务端ip和端口

#3、通信:发\收消息
phone.send('hello'.encode('utf-8'))
# phone.send(bytes('hello',encoding='utf-8'))
data = phone.recv(1024)
print(data)

# import time
# time.sleep(500)
#4、关闭
phone.close()

五、基于TCP协议的套接字编程(循环)

5.1服务器

import socket

#1、买手机
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM
# print(phone)

#2、插入/绑定手机卡
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8080))

#3、开机
phone.listen(5)  # 半连接池,限制的是请求数

#4、等待电话连接
print('start....')
while True:  # 连接循环
    conn, client_addr = phone.accept()  #(三次握手建立的双向连接,(客户端的ip,端口))
    # print(conn)
    print('已经有一个连接建立成功', client_addr)

    #5、通信:收\发消息
    while True:  # 通信循环
        try:
            print('服务端正在收数据...')
            data = conn.recv(1024)  #最大接收的字节数,没有数据会在原地一直等待收,即发送者发送的数据量必须>0bytes
            # print('===>')
            if len(data) == 0: break  #在客户端单方面断开连接,服务端才会出现收空数据的情况
            print('来自客户端的数据', data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    #6、挂掉电话连接
    conn.close()

#7、关机
phone.close()

5.2 客户端1

import socket

#1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#2、拨电话
phone.connect(('127.0.0.1', 8080))  # 指定服务端ip和端口

#3、通信:发\收消息
while True:  # 通信循环
    msg = input('>>: ').strip()  #msg=''
    if len(msg) == 0: continue
    phone.send(msg.encode('utf-8'))
    # print('has send----->')
    data = phone.recv(1024)
    # print('has recv----->')
    print(data)

#4、关闭
phone.close()

5.3客户端2

import socket

#1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#2、拨电话
phone.connect(('127.0.0.1', 8080))  # 指定服务端ip和端口

#3、通信:发\收消息
while True:  # 通信循环
    msg = input('>>: ').strip()
    phone.send(msg.encode('utf-8'))
    data = phone.recv(1024)
    print(data)

#4、关闭
phone.close()

六、地址占用问题

在重启服务端时可能会遇到:

[

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)

6.1 方法一

# 加入一条socket配置,重用ip和端口

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))

6.2方法二(Linux)

发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
vim /etc/sysctl.conf
编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后执行 /sbin/sysctl -p 让参数生效。
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

原文地址:https://www.cnblogs.com/randysun/p/11516884.html

时间: 2025-01-04 21:51:00

基于TCP协议的socket套接字编程的相关文章

基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 建立一个UDP协议的服务器 server.bind(("127.0.0.1",8080)) while True: data,addr = server.recvfrom(1024) server.sendto(data.upper(),addr) server

基于UDP协议的socket套接字编程

基于UDP协议的socket套接字编程 一.UDP套接字简单示例 1.1 服务器 import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议->UDP server.bind(('127.0.0.1', 8080)) while True: data, client_addr = server.recvfrom(1024) print('===>', data, client_addr) ser

102 基于UDP协议的socket套接字

目录 一.基于UDP协议的socket套接字编程 1.1 用法 1.2 udp协议的特点 1.3 实例 一.基于UDP协议的socket套接字编程 socket套接字包括使用TCP协议和UDP协议进行通讯 1.1 用法 socket指定使用UDP通讯协议server = socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM) 发送udp数据server.sendto(发送数据) 接收udp数据data, addr = server.recvfr

Learning-Python【28】:基于TCP协议通信的套接字

什么是 Socket Socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口.在设计模式中,Socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面,对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指定的协议. 所以,我们无需深入理解 TCP/UDP 协议,socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然就是遵循 TCP/UDP 标准的. 套接字的分类: 基于文件

Python 31 TCP协议 、socket套接字

1.TCP协议 可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割. (1)三次握手建链接(2)四次挥手断开链接(3)tcp协议的状态(4)syn洪水攻击与半连接池 1.一开始,建立连接之前服务器和客户端的状态都为CLOSED: 2.服务器创建socket后开始监听,变为LISTEN状态: 3.客户端请求建立连接,向服务器发送SYN报文,客户端的状态变味SYN_SENT: 4.服务器收到客

TCP协议与socket套接字

一.TCP协议 TCP协议建立双向通道 1.三次握手,建立连接: 客户端向服务端发送建立连接的请求  服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求  客户端接收到服务端发来的请求,返回接成功给服务端,完成双向连接 2.反馈机制: 客户端往服务端发送请求,服务端必须返回响应, 告诉客户端收到请求了,并且将服务端的数据一并返回给客户端. 洪水攻击:指的是通过伪造大量的请求,往对方服务器发送请求,导致对方服务器响应跟不上,以至于瘫痪. 半连接池listen: 限制用户在同一个时间段

socket 套接字编程

目录 SOCKET 一.基于TCP协议的socket套接字编程 1.1 什么是socket 1.2 套接字分类 1.3 套接字工作流程 二.基于udp协议的套接字编程 三.UDP协议和TCP协议的区别 3.1 udp协议的特点 3.2 UDP和TCP的区别 SOCKET 一.基于TCP协议的socket套接字编程 1.1 什么是socket ? socket是应用层和传输层之间的一个抽象层,我们经常把socket称为套接字,它是一组接口,把TCP/IP层的复杂操作抽象为几个简单的接口供应用层调用

网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1.A2和B2提供服务. Socket概述 ①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过“套接字”向网络发出请求或者应答网络请求. ②   Socket是连接运行在网络上的两个程序间的双向通信的端点. ③  

Python网络编程02/基于TCP协议的socket简单的通信

目录 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 2.socket 2.1 socket套接字 2.2 基于TCP协议的socket简单通信 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 1.单播:单独联系某一个人 2.广播:给所有人发送消息(群发) 3.比特流:bit就是0101跟水流一样的源源不断的发送01010101 4.以太网协议:将数据进行分组:一组称之为一帧,数据报 head|data head:18字节: