# socket

socket

1. 概述

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

在这里插入图片描述

3. socket基础

2. socket聊天室代码

  1. socket server代码的步骤一般如下

    在这里插入图片描述

    1. 服务器端

      1. 服务器首先初始化好socket
      2. 绑定这个socket服务器运行的ip地址和端口
      3. 监听这个服务器
      4. 等待socket连接,这个步骤会一直阻塞,直到有socket链接进来
      5. 当连接成功之后,服务器就可以读取客户端发送的socket消息
      6. 服务器可以选择给客户端回传socket消息
      7. 服务器关闭socket
    2. 客户端

      1. 客户端初始化socket
      2. 客户端去和服务器建立链接
      3. 客户端向服务器发送数据
      4. 客户端等待服务器相应数据
      5. 客户端关系socket
    3. 按照上述描述,python代码(伪)书写应该如下

        ss = socket() 
        ss.bind() 
        ss.listen() 
        inf_loop:
			  cs = ss.accept() 
			  comm_loop:
			      cs.recv()/cs.send() 
			      cs.close()
			  ss.close()
  1. python socket库基础知识

    1. 要创建套接字,必须使用 socket.socket()函数,它一般的语法如下。 socket(socket_family, socket_type, protocol=0)。socket.socket是new出来socket套接字对象,但是通信的运输层有tcp或者upd来通信. 网络层有ip协议来传输和本地[非网络的 AF_LOCAL/AF_UNIX]套接字来传输数据。所以我们需要配置socket_family和socket_type

    2. 套接字是网络编程中的一种通信机制,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

      1. socket_family

         1. AF_INET表示使用ipv4协议来传输
         2. AF_UNIX表示使用非网络的套接字来传输
        
      2. socket_type

        1. SOCK_STREAM 表示tcp协议
        2. SOCK_DGRAM 表示使用upd协议来连接
        
      3. 综合:

        所以说 tcpSock = socket(AF_INET, SOCK_STREAM)表示使用ip和tcp来进行通信
        
    3. s.bind():
      将地址(主机名、端口号对)绑定到套接字上

    4. ss.listen():

      设置并启动 TCP 监听器

    5. ss.accept():

      被动接受 TCP 客户端连接,一直等待直到连接到达(阻塞)

    6. s.recv():

      接受socket消息,请注意 上面的方法是接受连接

    7. s.send():

      发送 TCP 消息

    8. s.close():

      关闭套接字

  2. 服务器/客户端实际代码v1(简单的流程演示):

  3. 服务器代码:

          import socket

			bind_address = ("0.0.0.0",19527) #或者127.0.0.1本地回环网,0.0.0.0是默认换为内网的网址。			
			#申明
			ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
			#绑定地址和监听
			ss.bind(bind_address)
			ss.listen()
			#获取客户端socket对象和地址
			cli,addr = ss.accept()
			#获取tcp消息 一次1kb
			msg = cli.recv(1024)
			print(msg)
			#回送消息
			cli.send(b'get')
			ss.close()
  1. 客户端代码
import socket
			send_address = ("0.0.0.0",19527)
			cli = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
			#直接连接
			cli.connect(send_address)
			#发送数据
			cli.send(b'teset')
			#接受数据
			msg = cli.recv(1024)
			print(msg)
			cli.close()
  1. 服务器/客户端代码(更有交互性的代码)

    1. 说明:
      这次的代码,让服务器和客户端更有交互性,客户端输入消息后,服务器返回消息

    2. 代码:
      服务端:

import socket

		ss_address = ("0.0.0.0",19534)		#地址linux用0.0.0.0:n  实验,
												#windows用本机地址cmd中输出 ipconfig 查看
		ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
												#socket 连接对象,STREAM(stream)数据流 
												#socket.AF_INET使用ip4协议  socket.AF_INET6使用ip6
		ss.bind(ss_address)					#占用一个端口,ip 0.0.0.0:19534 本地用
		ss.listen(2)							#对端口进行监听,实时接收客户端的请求内容
		while True:							#建立循环,
		    cli,addr = ss.accept()	       #注意:accept()函数会返回一个元组
												#元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
		    print('收到来自ip为{}的连接'.format(addr))		#提示连接成功
		    									
		    #在连接的时候,进入循环
		    while True:
		        # 接受消息
		        data = cli.recv(1024)
		        if not data:					#当接收的内容为空不存在的时候,
		            break					#跳出最近的一次循环
		        print("发送请求内容为:{}".format(data.decode("utf-8")))
		        re_msg = "收到你的消息{}".format(data.decode('utf8'))  #定义变量接收客户端的消息
		        cli.send(re_msg.encode('utf8'))				#再将内容传给客户端
		    cli.close()

客服端:


import socket

cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  #创建一个名为cli客户端的socket对象
send_address =  ("0.0.0.0",19534)			#定义变量send_address 储存ip和端口
cli.connect(send_address)   			#连接服务端
while True:					
    neirong = input("输入内容:")		#输入传送的内容
    cli.sendall(bytes(neirong, encoding="utf8"))	#编码并且传送内容刚给服务端
    data = cli.recv(1024)							#接收服务端返回的内容
    if not data:										#判断为不为空
        break
    print(data.decode("utf8"))						#把服务端返回内容解码并打印
cli.close()
  1. 客户端接受http请求,并且返回http代码

    1. 说明:
      我们在获取http代码的时候,获取http代码的库文件,或者浏览器底层,就是用了socket来获取http报文,我们可以模拟底层的报文请求方式,来深一步的了解http报文结构

    2. 代码:

	# 使用socket获取http报文
	import socket
	from urllib.parse import urlparse
	
	# 初始化socket
	ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	domain = "https://www.baidu.com"
	url = urlparse(domain)
	host = url.netloc
	path = url.path
	if path == "":
	    path = "/"
	ss.connect((host, 80))
	#'\r'的本意是回到行首,'\n'的本意是换行
	data = "GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\nUser-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n\r\n".format(
	    path, host).encode('utf8')
	ss.send(data)
	res = b""
	#报文就不像聊天数据那么小了 需要循环的拼接报文
	while True:
	    d = ss.recv(1024)
	    if d:
	        res += d
	    else:
	        break
	print(res.decode('utf8'))
	ss.close()
  1. 多线程聊天代码演示

    1. 说明: 刚才的版本只能接受一个连接,我们可以使用多线程版本来优化代码

    2. 代码:

import socket
		import threading
		
		def cli_msg(cli,addr):
		    print('收到来自ip为{}的连接'.format(addr))
		    #在连接的时候,进入循环
		    while True:
		        # 接受消息
		        data = cli.recv(1024)
		        if not data:
		            break
		        re_msg = "收到你的消息{}".format(data.decode('utf8'))
		        cli.send(re_msg.encode('utf8'))
		    cli.close()
		    return True
		
		ss_address = ("0.0.0.0",19534)
		ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		ss.bind(ss_address)
		ss.listen(2)
		
		
		while True:
		    #获取连接
		    cli,addr = ss.accept()
		    threading.Thread(target=cli_msg,args=(cli,addr)).start()
import socket

		ss_address = ("0.0.0.0",19534)
		
		ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		
		ss.connect(ss_address)
		
		while True:
		    data = input('请输入消息:')
		    if not data:
		        break
		    ss.send(data.encode('utf8'))
		    print(ss.recv(1024).decode('utf8'))
		
		
		ss.close()

猜你喜欢

转载自blog.csdn.net/weixin_43097301/article/details/84340744