网络编程
推荐链接:‘网络编程’ http://www.cnblogs.com/Eva-J/articles/8244551.html#_label2
服务端一直是监听状态的。
客户端单工通信请求连接服务端,服务端通过然后请求客户端建立连接,单工。客户端接收到通过并回复。然后建立起双工通信。合并了2,3条信息
有收必有发,收发必相等。
断开可以是客户端也可以是服务端先。
建立连接后,后面的发送是基于连接下发送消息。即使没有连接,服务端和客户端也可以互发消息的。
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字
sk.listen() #监听连接,个数
conn,addr = sk.accept() #接受客户端连接,阻塞
ret = conn.recv(1024) #接收客户端信息
print(ret) #打印客户端信息
conn.send(b'hi') #向客户端发送信息
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
创建对象,
绑定ip端口
监听
accept和connect实现了三次握手的过程
conn.close()和sk.accept().close区别:
conn.close()为了断开单个连接的客户端
sk.accept().close服务端断开,所有客户端都连接不上了
bind ip 端口 ip为127的只能自己访问,IP为自己的ip可以提供给他人访问
sk.send("".encode())这里编码是啥,服务端ret = conn.recv(1024)就要解码 ret.decode
sk.send(b""),服务端ret = conn.recv(1024)
收发对应上
input实现聊天。
发送消息为input信息
服务端conn.send(b'hi') ret = conn.recv(1024)
为了实现多次聊天
将input消息发送消息,接收打印消息放入死循环 关闭和accept都不能在死循环里。
为了实现退出聊天,加个对输入消息的判断,退出死循环:
客户端发送退出,服务端接收到的就退出,
服务端发送退出,服务端退出循环就直接关闭连接然后关闭sk,客户端报错
外层再加个while循环,内层循环在conn,addr = sk.accept(),conn.close() 直接,这样关闭一个连接,那么可以进行下一个连接:
ret=sk.send(input(">>>").encode("utf-8"))如果有变量接收,那么自动打印ret字节长度
input在这里只能实现一来一回
多人能同时聊天,同时互连,发消息给谁-服务端进行转发
sk.listen(n)允许多少个人等待
-----udp
服务端recvfrom这样知道是谁发的,
客户端recv就可以,因为已经知道是发给谁,只要内容就可以了
tcp不能1对多因为占线了,双层循环
udp实现了服务端1对多(聊天)(加上识别身份)
--------udp创建
udp服务端:
import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字
udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字
while True:
msg,addr = udp_sk.recvfrom(1024)
if msg.decode("utf-8").upper()=="Q":break
print(msg.decode())
a=input(">>>").encode("utf-8")
udp_sk.sendto(a,addr) # 对话(接收与发送)
if a.decode().strip(">>>").upper() == "Q": break
udp_sk.close()
udp客户端:
import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字
udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字
while True:
msg,addr = udp_sk.recvfrom(1024)
if msg.decode("utf-8").upper()=="Q":break
print(msg.decode())
a=input(">>>").encode("utf-8")
udp_sk.sendto(a,addr) # 对话(接收与发送)
if a.decode().strip(">>>").upper() == "Q": break
udp_sk.close()
udp服务端:
创建一个udp对象加参数type=socket.SOCK_DGRAM,
对象.bind绑定ip端口
接收信息 对象.recvfrom(字节数)
发送信息 对象.sendto(字节类型数据)
关闭对象 对象.close
udp客户端:
创建一个udp对象加参数socket.socket(type=socket.SOCK_DGRAM)
发送给谁:对象.sendto(字节内容,ip端口元组)
接收信息:对象.recv(字节数)
不需要关闭,udp对象没有关闭方法。
1)二者接收到的内容显示一下
2)想不断接收发送那就将接收数据发送数据放到while循环
3)想停止客户端while循环那就判断发送的指定字符为Q退出循环
4)客户端退出while循环停止服务端跟随停那么服务端判断接收到指定字符Q,break循环
5)服务端突然停
6)想退出while循环可以写成一行:if a.decode().strip(">>>").upper()=="Q":break
7)服务端未开或服务端突然停止,客户端发送数据报错:[WinError 10054] 远程主机强迫关闭了一个现有的连接。
8)服务端突然停止,客户端在等待服务端回复,似乎客户端会卡住,不退出,输入内容因为不是在发送阶段所以没反应
9)如果想服务端和客户端有个想要退出Q,那么都是在自己这里发送之后判断发送是否为Q,在对方接收后面打印接收之前就可以判断是否为Q,是则breck循环。一般两方都停的适用于tcp的连接。
10)如果想给每个和服务端通话的客户端加个标签,那么只需要将客户端发送的数据加个标签
11)udp没有服务端没有listen监听端口,它可以服务端1对多通信。给每个客户端加个name,将name发送出去以识别是谁
12)客户端 sendto忘记加IP端口元组,报错:sendto() takes 2 or 3 arguments (1 given)
13)服务端sendto(字节内容,ip端口元组),[1]客户端 对象.recvfrom(1024)接收到的是个元组(字节内容,ip端口元组)[2]客户端 对象.recv(1024)接收到的是字节内容,比如:b'2'
报错:
1)
2)
3)udp服务端,udp客户端,将客户端的(type=socket.SOCK_DGRAM)改为()报错:
OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
sendto的问题:
正确1:服务端udp_sk.sendto(a,addr) 客户端: back_msg,addr=udp_sk.recvfrom(1024)
正确2:服务端:udp_sk.sendto(a,addr) 客户端:back_msg=udp_sk.recv(1024)
1)服务端: udp_sk.send(a,addr) 客户端 back_msg,addr=udp_sk.recvfrom(1024)
报错:TypeError: an integer is required (got type tuple)
2)服务端:udp_sk.send(a) 客户端 back_msg,addr=udp_sk.recvfrom(1024)
报错:OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
3)服务端:udp_sk.sendto(a) 客户端:back_msg,addr=udp_sk.recvfrom(1024)
报错:TypeError: sendto() takes 2 or 3 arguments (1 given)
4)服务端:udp_sk.sendto(a,addr) 客户端:back_msg,addr=udp_sk.recv(1024)
客户端报错:ValueError: not enough values to unpack (expected 2, got 1)
综上:udp用sendto,发送内容和IP端口组成的元组,接收用recvfrom则接收两个内容,用recv只是接收发送的数据。
TCP
tcp连接:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听链接
conn,addr = sk.accept() #接受客户端链接
ret = conn.recv(1024) #接收客户端信息
print(ret) #打印客户端信息
conn.send(b'hi') #向客户端发送信息
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
-----结果:
b'hello!'
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
sk.send(b'hello!')
ret = sk.recv(1024) # 对话(发送/接收)
print(ret)
sk.close() # 关闭客户套接字
------------结果:
b'hi'
tcp连接实现一直通话
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听链接
conn, addr = sk.accept() # 接受客户端链接。产生一个阻塞。时
while True:
ret = conn.recv(1024).decode("utf-8") #接收客户端信息
print(ret) #打印客户端信息
msg=input(">>>")
conn.send(msg.encode("utf-8")) #向客户端发送信息
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
----------结果:
c1
>>>s1
c2
>>>
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
while True:
msg=input(">>>")
sk.send(msg.encode("utf-8"))
ret = sk.recv(1024).decode("utf-8") # 对话(发送/接收)
print(ret)
sk.close() # 关闭客户套接字
---------结果:
>>>c1
s1
>>>c2
tcp退出一直聊天
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听链接
conn, addr = sk.accept() # 接受客户端链接
while True:
ret = conn.recv(1024).decode("utf-8") #接收客户端信息
if ret.upper()=="Q":break
print(ret) #打印客户端信息
msg=input(">>>")
conn.send(msg.encode("utf-8")) #向客户端发送信息
if msg.upper()=="Q":break
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
------------结果:
c1
>>>c2
Process finished with exit code 0
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
while True:
msg=input(">>>")
sk.send(msg.encode("utf-8"))
if msg.upper()=="Q":break
ret = sk.recv(1024).decode("utf-8") # 对话(发送/接收)
if ret.upper()=="Q":break
print(ret)
sk.close() # 关闭客户套接字
----------------结果:
>>>c1
c2
>>>q
Process finished with exit code 0
tcp连接,退出一个连接后可以进入下一个连接:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听连接,允许等待的个数
while True:
conn, addr = sk.accept() # 接受客户端连接
while True:
ret = conn.recv(1024).decode("utf-8") #接收客户端信息
if ret.upper()=="Q":break
print(ret) #打印客户端信息
msg=input(">>>")
conn.send(msg.encode("utf-8")) #向客户端发送信息
if msg.upper()=="Q":break
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
while True:
msg=input(">>>")
sk.send(msg.encode("utf-8"))
if msg.upper()=="Q":break
ret = sk.recv(1024).decode("utf-8") # 对话(发送/接收)
if ret.upper()=="Q":break
print(ret)
sk.close() # 关闭客户套接字
tcp连接不同的用户不同的名字识别:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听连接,允许等待的个数
while True:
conn, addr = sk.accept() # 接受客户端连接
while True:
ret = conn.recv(1024).decode("utf-8") #接收客户端信息
if ret.upper()=="Q":break
print(ret) #打印客户端信息
msg=input(">>>")
conn.send(msg.encode("utf-8")) #向客户端发送信息
if msg.upper()=="Q":break
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
--------结果:
小马过河1234QQ:xiao
>>>q
小郭吹雪1234QQ:ming
>>>
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
name_and_qq="小郭吹雪1234QQ"
while True:
msg=input(">>>")
sk.send((name_and_qq+":"+msg).encode("utf-8"))
if msg.upper()=="Q":break
ret = sk.recv(1024).decode("utf-8") # 对话(发送/接收)
if ret.upper()=="Q":break
print(ret)
sk.close() # 关闭客户套接字
1.基于tcp协议实现聊天基础需求:
# 1.server和client端连接之后,能知道对面这个人是哪一个好友 qq号
# 2.不同好友的聊天颜色不同 https://www.cnblogs.com/Eva-J/p/8330517.html
import random
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字
sk.listen() #监听连接,允许等待的个数
while True:
color=random.randint(30,37)
color="\033[amb\033[0m".replace("a",str(color))
conn, addr = sk.accept() # 接受客户端连接
while True:
ret = conn.recv(1024).decode("utf-8") #接收客户端信息
if ret.upper()=="Q":break
print(color.replace("b",ret)) #打印客户端信息
msg=input(">>>")
conn.send(msg.encode("utf-8")) #向客户端发送信息
if msg.upper()=="Q":break
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
# ----------结果:
# 小马过河1234QQ:xiao
# >>>q
# 小郭吹雪1234QQ:ximgn
# >>>
import socket
sk = socket.socket() # 创建客户套接字
sk.connect(('127.0.0.1',9000)) # 尝试连接服务器
name_and_qq="小马过河1234QQ"
while True:
msg=input(">>>")
sk.send((name_and_qq+":"+msg).encode("utf-8"))
if msg.upper()=="Q":break
ret = sk.recv(1024).decode("utf-8") # 对话(发送/接收)
if ret.upper()=="Q":break
print(ret)
sk.close() # 关闭客户套接字