网络编程之Socket

一.Socket层

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.
把复杂的TCP/IP协议族隐藏在Socket接口后面.让Socket去组织数据,以符合指定的协议
可以理解socket就是一个模块,也可理解成ip+port
只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信

2.套接字(socket):

一开始,套接字被设计用在同一台主机上多个应用程序之间的通讯
套接字有两种:
基于文件型:套接字家族的名字:AF_UNIX
基于网络型:套接字家族的名字:AF_INET

3.socket参数

socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
创建socket对象的参数说明:
SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。
SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。
proto 协议号通常为零,可以省略。
fileno 如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。

4.服务端套接字函数

s.bind()     绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数:s.connect() 主动初始化TCP服务器连接

5.公共用途的套接字函数:

s.recv()    接收TCP数据
s.send() 发送TCP数据(待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall()发送完整的TCP数据(待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getsockname() 当前套接字的地址
s.close() 关闭套接字

####
阻塞####
阻塞:如果阻塞模式则等待数据
非阻塞:如果非阻塞模式有数据返回数据、无数据直接返回报错
UDP中服务端有几个recvfrom就要对应几个sendinto
sk.setblocking(bool)
是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错

二.基于TCP协议的socket

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
简单通信:server端
import socket
sk=socket.socket()   #创建了一个socket对象
#sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 如果端口冲突加上这个
sk.bind(('127.0.0.1',9000))  #绑定一台机器的(ip,端口)
sk.listen()          ##建立监听等待别人连接
corn,add=sk.accept() #阻塞:在这里等待直到接到一个连接
# conn是连接
# addr是对方的地址
corn.send(b'hello') #和对方打招呼
msg=corn.recv(1024)  #接收对方的信息
print(msg)
corn.close()  #关掉连接
sk.close()
View Code

client端

import socket
sk=socket.socket()
sk.connect(("127.0.0.1",9000))
ret=sk.recv(1024)
print(ret)
sk.send(b'HELLO')
sk.close()
View Code

简单的聊天例子:server端

import socket
sk=socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
corn,add=sk.accept()
while True:
    inp=input("《《")
    if inp == "q":
        corn.send(inp.encode("utf-8"))
        break
    corn.send(inp.encode("utf-8"))
    msg=corn.recv(1024)
    if msg.decode("utf-8") =="q":break
    print(msg.decode("utf-8"))
corn.close()
sk.close()
View Code

client端

import socket
sk=socket.socket()
sk.connect(("127.0.0.1",9000))
while True:
    ret=sk.recv(1024)
    if ret.decode("utf-8") == "q":break
    print(ret.decode("utf-8"))
    sed=input("<<")
    if sed.encode(("utf-8")) == "q":
        sk.send(sed.encode(("utf-8")))
        break
    sk.send(sed.encode(("utf-8")))
sk.close()

三.基于UDP协议的socket

udp是无链接的,先启动哪一端都不会报错

简单通信:server端

import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
# 建立一个socket对象,指定以UDP协议的形式来连接
sk.bind(("127.0.0.1",9000)) # 指定服务的地址
msg,add=sk.recvfrom(1024) # 接收消息,发送端的地址
print(msg)
sk.sendto(b'hello',add)  #给发送端回复消息
sk.close() #关闭socket连接
View Code

client端


import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.sendto(b"HELLO",("127.0.0.1",9000))  ##直接给服务器发送一段消息
msg,add=sk.recvfrom(1024)  # #接收对面的回信
print(msg)
sk.close()
View Code

简单的聊天例子:server端
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1",9000))
while True:
    msg,add=sk.recvfrom(1024)
    print("来自%s的一条消息:%s"%(add,msg.decode("utf-8")))
    message=input("》》")
    sk.sendto(message.encode("utf-8"),add)
sk.close()
View Code

client端

import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
while True:
    message = input("》》")
    add=("127.0.0.1",9000)
    sk.sendto(message.encode("utf-8"), add)
    msg,add=sk.recvfrom(1024)
    print(msg.decode("utf-8"))
sk.close()
View Code
时间服务器:客户端每隔一段时间发送请求到服务端,发送时间的格式
简单通信:server端
import time
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1",9000))
while True:
    msg,add=sk.recvfrom(1024)
    msg=time.strftime(msg.decode("utf-8"))
    sk.sendto( msg.encode("utf-8"),add)
sk.close()
View Code

client端

import time
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
while True:
    add=("127.0.0.1",9000)
    msg_time="%Y-%m-%d %H:%M:%S"
    sk.sendto(msg_time.encode("utf-8"),add)
    msg,add=sk.recvfrom(1024)
    print(msg.decode("utf-8"))
    time.sleep(1)
sk.close()
View Code
 
 
 
 
 
 

原文地址:https://www.cnblogs.com/zgf-666/p/8613367.html