网络编程 socket套接字

Posted xp1315458571

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程 socket套接字相关的知识,希望对你有一定的参考价值。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

一、套接字了解

socket层:

那么多脏活累活我们不想干就全部交给socket来做,它是一组接口,把复杂的TCP/IP协议族隐藏在Socket接口后面

其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。

技术图片

基于网络的套接字家族:

所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我们只使用AF_INET

二、套接字(socket)初使用

1.基于TCP协议的socket

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

127.0.0.1本机回还地址:
      只能自己识别自己 其他人无法访问

send与recv两边对应:
      不要出现两边都是相同的情况

recv是跟内存要数据:

      应用程序所有数据都是跟自己的内存要,数据可能来自于硬盘或网络传输
      

技术图片

 

#server端

import socket

server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
server.bind((127.0.0.1,8080))  # bind((host,port))  插电话卡  绑定服务端自己的ip和端口
server.listen(5)  # 开机    半连接池

conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞:等待接收请求
data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞:等待接收数据
print(data)
conn.send(bhello baby~)  # 给别人回话

conn.close()  # 挂电话
server.close()  # 关机

#client

import socket

client = socket.socket()  # 拿电话
client.connect((127.0.0.1,8080))  # 拨号
#写的是对方的ip和port

client.send(bhello world!)  # 对别人说话
data = client.recv(1024)  # 听别人说话
print(data)

client.close()  # 挂电话

 

 

#在重启服务端时(特别是mac系统)可能会遇到以下报错,是因为系统还没有回收端口,端口被占用,加入两句代码重用IP和端口即可:


技术图片

 


 

#导入模块 加入一条socket配置,重用ip和端口
import socket
from socket import SOL_SOCKET,SO_REUSEADDR

server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
server .setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
server.bind((127.0.0.1,8080))  # bind((host,port))  插电话卡  绑定服务端自己的ip和端口
server.listen(5)  # 开机    半连接池

conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞:等待接收请求
data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞:等待接收数据
print(data)
conn.send(bhello baby~)  # 给别人回话

conn.close()  # 挂电话
server.close()  # 关机

 

2. 循环通信 和 连接循环

#让客户端和服务端可以多次通讯

技术图片

 

 #改进 通讯循环 和 链接循环

 

技术图片

 

 

技术图片
import socket

"""
服务端
    固定的ip和port
    24小时不间断提供服务
"""
server = socket.socket()  # 生成一个对象
server.bind((127.0.0.1,8080))  # 绑定ip和port
server.listen(5)  # 半连接池

while True:
    conn, addr = server.accept()  # 等到别人来  conn就类似于是双向通道
    print(addr)  # (‘127.0.0.1‘, 51323) 客户端的地址
    while True:
        try:
            data = conn.recv(1024)
            print(data)  # b‘‘  针对mac与linux 客户端异常退出服务端不会报错 只会一直收b‘‘
            if len(data) == 0:break
            conn.send(data.upper())
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()
循环通信 服务端

 

技术图片
import socket

client = socket.socket()
client.connect((127.0.0.1,8080))

while True:
    msg = input(>>>:).encode(utf-8)
    if len(msg) == 0:continue
    client.send(msg)
    data = client.recv(1024)
    print(data)
循环通信 客户端

三、粘包问题

黏包现象只发生在tcp协议中:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

 

1.粘包类型

#发送方粘包

TCP特点:

会将数据量比较小的并且时间间隔比较短的数据一次性打包发送给对方

发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。

若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

技术图片

#指定接收长度

指定接收长度虽然可以解决,但是你怎么能知道客户端出来什么数据呢?

技术图片

 

技术图片
import socket


server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
server.bind((127.0.0.1,8080))  # bind((host,port))  插电话卡  绑定ip和端口
server.listen(5)  # 开机    半连接池


conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
data = conn.recv(5)  # 听别人说话 接收1024个字节数据          阻塞
print(data)
data = conn.recv(5)  # 听别人说话 接收1024个字节数据          阻塞
print(data)
data = conn.recv(4)  # 听别人说话 接收1024个字节数据          阻塞
print(data)



import socket
client = socket.socket()
client.connect((127.0.0.1,8080))

client.send(bhello)
client.send(bworld)
client.send(bbaby)
指定接收长度

#接收方造成的

接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

技术图片
#_*_coding:utf-8_*_
from socket import *
ip_port=(127.0.0.1,8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)


conn,addr=tcp_socket_server.accept()


data1=conn.recv(2) #一次没有收完整
data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

print(----->,data1.decode(utf-8))
print(----->,data2.decode(utf-8))

conn.close()
服务端
技术图片
#_*_coding:utf-8_*_
import socket
BUFSIZE=1024
ip_port=(127.0.0.1,8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)


s.send(hello egg.encode(utf-8))
客户端

 

2.  struct 模块

 

以上是关于网络编程 socket套接字的主要内容,如果未能解决你的问题,请参考以下文章

网络编程(part11)--socket模块方法及socket套接字属性

4-socket套接字编程

网络编程之套接字socket

10.网络编程之socket

网络编程socket套接字及其使用

socket