02Python学习笔记之二.十【网络编程初步】2019-08-26

章节号 内容            
1图片格式(png) 宽度大于620px,保持高宽比减低为620px
12 123
1-1-1 方法
1-1-1 方法

第1章节 网路初步

  • 1-1 网路初步—tcp ip协议(族)

  4层次:链路层、网络层、传输层、应用层
  7层次:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层



  • 1-2 端口

  就是用来区分不同的进程。范围从0-65535。
  知名端口:大家都知道的端口。范围:0-1023
  动态端口:动态分配的端口。范围:1024-65535
  查看端口:netstat -an

li@li-ThinkPad-T420s:~$ netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:139             0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:445             0.0.0.0:*               LISTEN     
tcp        0      0 192.168.0.119:53582     182.242.213.227:443     ESTABLISHED
tcp        0      0 192.168.0.119:42430     180.101.136.110:443     ESTABLISHED
tcp        0      0 192.168.0.119:51912     182.131.6.245:443       ESTABLISHED
tcp        0      0 192.168.0.119:53408     52.37.42.64:443         ESTABLISHED
tcp6       0      0 :::139                  :::*                    LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN     
tcp6       0      0 :::445                  :::*                    LISTEN     
udp        0      0 127.0.0.53:53           0.0.0.0:*                          
udp        0      0 0.0.0.0:68              0.0.0.0:*                          
udp        0      0 192.168.0.255:137       0.0.0.0:*                          
udp        0      0 192.168.0.119:137       0.0.0.0:*                          
udp        0      0 0.0.0.0:137             0.0.0.0:*                          
udp        0      0 192.168.0.255:138       0.0.0.0:*                          
udp        0      0 192.168.0.119:138       0.0.0.0:*                          
udp        0      0 0.0.0.0:138             0.0.0.0:*                          
udp        0      0 0.0.0.0:51687           0.0.0.0:*                          
udp        0      0 0.0.0.0:631             0.0.0.0:*                          
udp        0      0 0.0.0.0:5353            0.0.0.0:*                          
udp6       0      0 :::55239                :::*                               
udp6       0      0 :::5353                 :::*                               
raw6       0      0 :::58                   :::*                    7          
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ]         DGRAM                    36076    /run/user/1000/systemd/notify
unix  2      [ ]         DGRAM                    24517    /run/user/120/systemd/notify
unix  2      [ ACC ]     SEQPACKET  LISTENING     16396    /run/udev/control
unix  2      [ ACC ]     STREAM     LISTENING     39171    /tmp/sogou-qimpanelli
unix  2      [ ACC ]     STREAM     LISTENING     36185    /tmp/ssh-nNqqPOVeFdvP/agent.3540
unix  2      [ ACC ]     STREAM     LISTENING     36079    /run/user/1000/systemd/private
unix  2      [ ACC ]     STREAM     LISTENING     24520    /run/user/120/systemd/private
unix  2      [ ACC ]     STREAM     LISTENING     36083    /run/user/1000/gnupg/S.gpg-agent.ssh
unix  2      [ ACC ]     STREAM     LISTENING     23412    /run/user/120/gnupg/S.gpg-agent.browser
unix  2      [ ACC ]     STREAM     LISTENING     36084    /run/user/1000/gnupg/S.gpg-agent.browser
unix  2      [ ACC ]     STREAM     LISTENING     36085    /run/user/1000/gnupg/S.gpg-agent.extra
unix  2      [ ACC ]     STREAM     LISTENING     23413    /run/user/120/pulse/native
unix  2      [ ACC ]     STREAM     LISTENING     36086    /run/user/1000/gnupg/S.dirmngr
unix  2      [ ACC ]     STREAM     LISTENING     23414    /run/user/120/bus
unix  2      [ ACC ]     STREAM     LISTENING     36087    /run/user/1000/bus
unix  2      [ ACC ]     STREAM     LISTENING     23415    /run/user/120/gnupg/S.gpg-agent.extra
unix  2      [ ACC ]     STREAM     LISTENING     36088    /run/user/1000/gnupg/S.gpg-agent
unix  2      [ ACC ]     STREAM     LISTENING     23416    /run/user/120/gnupg/S.dirmngr
unix  2      [ ]         DGRAM                    28191    /var/lib/samba/private/msg.sock/1031
unix  2      [ ACC ]     STREAM     LISTENING     23417    /run/user/120/gnupg/S.gpg-agent.ssh
.
.
.

  端口的用处:一个ip地址可以提供多种服务,使用端口来区分不同的服务功能。如80的http,21的ftp。
  为什么不用pid?多台电脑中,pid相同的程序,可能并不是同一种类的程序。

  • 1-3 ip地址

  作用:在逻辑上唯一的标记一台电脑。
  c类地址    192.  168.   1.    1
  二进制表现:1100000.10101000.00000001.00000001



  私有ip:10.0.0.0-10.255.255.255
      172.16.0.0-172.31.255.255
      192.168.0.0-192.168.255.255

  • 1-4 socket的简介(要用2台电脑测试)

  本地进程间通信(IPC),如果在同一台电脑上,可以使用队列、同步等。
  网络间进程的通信,使用socket套接字。
  ip区分电脑,端口确定程序,协议确定通信细节,三确定就可以通信。

In [1]: import socket

In [3]: ?socket.socket()
Init signature: socket.socket(family=, type=, proto=0, fileno=None)
Docstring:      A subclass of _socket.socket adding the makefile() method.
File:           /usr/lib/python3.6/socket.py
Type:           type

In [4]: help(socket.socket)
Help on class socket in module socket:

class socket(_socket.socket)
 |  A subclass of _socket.socket adding the makefile() method.
 |  
 |  Method resolution order:
 |      socket
 |      _socket.socket
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __enter__(self)
 |  
 |  __exit__(self, *args)
 |  
 |  __getstate__(self)
 |  
 |  __init__(self, family=, type=, proto=0, fileno=None)
 |      Initialize self.  See help(type(self)) for accurate signature.
.
.
.

  下面进行简单的sockte代码演示,使用udp协议发送。

import socket
#创建UDP套接字
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#设置接收方的ip和端口号
addr=("192.168.0.108",8080)
#python3注意这里要加上一个字母`b`,否则产生下面的报错
data=b"hello socket"
#发送!!!!!
us.sendto(data,addr)
#关闭
us.close()
Exception has occurred: TypeError
a bytes-like object is required, not 'str'
  File "/home/li/Desktop/py/ceshi.py", line 5, in 
    us.sendto(data,addr)

  在接收方我们使用一个软件“网络调试助手”来辅助完成。按照图示设置完毕后,发送方直接运行程序,即可接收到信息如图示。


  • 1-5 端口的问题、绑定端口

  地址、端口,协议,三者缺一不可。
  UDP类比于写信。有个地址就可以邮寄出去。每封信都有地址。
  TCP类比于打电话。要先建立通路。才开始讲话。

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
addr=("192.168.0.108",8080)
data=b"hello socket"
us.sendto(data,addr)
us.sendto(data,addr)
us.sendto(data,addr)
us.close()

  代码如上图,我们连续运行四次这段代码,看接收端的情况:

【Receive from 192.168.0.119 : 46425】:hello sockethello sockethello socket
【Receive from 192.168.0.119 : 52666】:hello sockethello sockethello socket
【Receive from 192.168.0.119 : 33521】:hello sockethello sockethello socket
【Receive from 192.168.0.119 : 34876】:hello sockethello sockethello socket

  可以看到每次发送的端口都是不一样的。
  PS:在同一个OS中,如果一个端口被占用了,那么其他的程序就不能再使用。很可能这个程序就要出错。
  如何让自己的端口不是随机呢?那就要用到端口绑定!

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
addr=("192.168.0.108",8080)

#这里是关键
#如果不写ip,就表示本机的任何一个ip。baddr=("",7787)
baddr=("192.168.0.119",7787)
data=b"hello socket"

#这里是关键
us.bind(baddr)
us.sendto(data,addr)
us.sendto(data,addr)
us.sendto(data,addr)
us.close()
【Receive from 192.168.0.119 : 7787】:hello sockethello

  一般来说,发送方不绑定。
  接收方要绑定,为服务方。
  下面编写一个接收数据的小程序:

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

baddr=("",7787)

us.bind(baddr)

data=us.recvfrom(1024)
print(data)
us.close()

  运行后程序会阻塞住,等待接收数据。



  如上图在另一端发送数据“123”,程序将自动解除阻塞并打印接收到的数据。

(b'123', ('192.168.0.108', 8080))
  • 1-6 python3的编码问题及解决

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
addr=("192.168.0.108",8080)

#这里是关键
#如果不写ip,就表示本机的任何一个ip。baddr=("",7787)
baddr=("192.168.0.119",7787)
data=bytes("我的".encode("utf-8"))

#这里是关键
# us.bind(baddr)
us.sendto(data,addr)
us.sendto(data,addr)
us.sendto(data,addr)
us.close()
data=bytes("123aaa".encode("utf-8"))

  这里使用了encode()编码功能把字符串进行了utf-8的编码,接收方在接收汉字的时候呈现了乱码(倒数第二和第三行),那么如何解决这个问题呢?

data=bytes("我的".encode("gb2312"))
【Receive from 192.168.0.119 : 38276】:我的我的我的

  ↑这里得到一个思考,那就是如果你发送的数据对方接收到了是乱码,则一定要考虑字符编码的一致性问题。


# 对str进行解码操作,使用gb2312的方式来解码

str.decode("gb2312"))

  ↓下面看一下元组的解包操作。

In [1]: a=(1111,2222)

In [2]: a
Out[2]: (1111, 2222)

In [3]: b,c=a

In [4]: b
Out[4]: 1111

In [5]: c
Out[5]: 2222

  中文网站的数据,要么是utf-8,要么是gb2312

  • 1-7 网络通信大体过程

  • 1-8 简单的聊天室

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

baddr=("",7788)

us.bind(baddr)

while True:
        data=us.recvfrom(1024)
        print(data)

  ↑不停的接收数据,只要收到就打印出来。

li@li-ThinkPad-T420s:~/Desktop/py$ cd /home/li/Desktop/py ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /usr/bin/python3 /home/li/.vscode/extensions/ms-python.python-2019.8.30787/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 42633 /home/li/Desktop/py/ceshi=======.py 
(b'1234', ('192.168.0.108', 8081))
(b'1234', ('192.168.0.108', 8081))
(b'1234', ('192.168.0.108', 8081))
(b'1234', ('192.168.0.108', 8081))
(b'1234', ('192.168.0.108', 8081))
(b'1234', ('192.168.0.108', 8081))
Terminated

  发送方使用网络调试助手即可。

  • 1-9 echo服务器

  接收到数据后,给予适当的反馈

import socket
us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

baddr=("",7788)

us.bind(baddr)

while True:
        data=us.recvfrom(1024)
        print(data)
        #关键在此句
        us.sendto(b"echo",data[1])
【2019-08-27 08:23:37:985】echo
【2019-08-27 08:23:38:720】echo
【2019-08-27 08:23:39:736】echo
【2019-08-27 08:23:40:329】echo
【2019-08-27 08:23:41:364】echo
【2019-08-27 08:23:42:395】echo
【2019-08-27 08:23:43:427】echo

  ↑网络调试助手收到的反馈。

  • 1-10 多线程模拟聊天程序


  ↑含服务器的聊天软件的大致过程

import socket
import threading
from threading import Thread
addr=()

def rec():
    while True:
        global addr
        data=us.recvfrom(1024)
        if addr== ():
            addr=data[1]
        print("\r>>"+ str(data[0].decode("gb2312")))
        print(">>"+ str(data[1]))
        


def sed():
    while True:
        d=input("\r<<1").encode("gb2312")
        sdata=bytes(d)
        if addr== ():
            print("waiting for some one")
        else:
            us.sendto(sdata,addr)    


us=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
baddr=("",7788)
us.bind(baddr)

t1=Thread(target=rec)
t2=Thread(target=sed)

t1.start()
t2.start()

t1.join()
t2.join()
li@li-ThinkPad-T420s:~/Desktop/py$ cd /home/li/Desktop/py ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /usr/bin/python3 /home/li/.vscode/extensions/ms-python.python-2019.8.30787/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 40533 /home/li/Desktop/py/ceshi.py 
<<14234234
waiting for some one
<<1234234
waiting for some one
>>1234
>>('192.168.0.108', 8081)
>>1234412341234
>>('192.168.0.108', 8081)
fasfsa
<<1asfsafd
<<1asdfasfd
<<1afdasfd
<<1Terminated
【2019-08-27 08:30:58:590】fasfsa
【2019-08-27 08:30:59:402】asfsafd
【2019-08-27 08:31:00:175】asdfasfd

  ↑聊天的多线程实现,一个线程等待接收,一个线程等待输入,不会造成整个程序的阻塞。python端先等待对方发送信息,接收到对方的ip和端口信息后再发送。

  • 1-11 wireshark


  ↑安装一定要勾选此选项。


  • 1-12 tftp分析

  首先下载tftp


  打开后,点击Browse,选定一个文件路径,作为下载支持路径。此刻下载服务器已经搭建好。
  下面我们开始编写一个下载器。首先:
  思考如下问题:什么叫下载,它的过程是什么?
  创建空文件,写数据,关闭。相当于接收。

程序概念:
f=open("文件名","bw")
while True:
  rec=udpsocket.recvfrom(1024)
  if xxx:
    没有数据
    break
  else:
    f.write(rec)

  思考如下问题:什么叫上传?相当于发送。

程序概念:
us.sendto(sdata,addr)   

  那么如何与服务器端进行连接呢?换句话来说,协议是什么呢?
  RFC 1350 - The TFTP Protocol (Revision 2)
  RFC 959 - File Transfer Protocol


  本例用的程序默认服务端口为69
  1、客户端按照读写请求的格式,向服务器发送请求。
  2、服务器向客户端发送数据包格式的数据。数据包最大516字节,一旦数据包小于516字节,代表整个文件传输完毕。如果是操作码3,则表示数据正确,你要回复信息,格式为ACK
  如果文件不存在,服务器返回ERROR格式的错误信息。收到这个,不需要回复。
  3、服务器给你发送信息,是随机端口。==69==只接收下载请求,确认包全部发往==随机端口==。
  如何再windows下查看端口??使用cmd

C:>>netstat -ano | findstr 69
UDP     0.0.0.0:69    *:*                   8720

  找到69对应的进程id(假如为8720)。

C:>>tasklist | findstr 8720
tftp64.exe       8720 Console       1      30,764 K

  现在已经确定端口号无误,可以开始了。
  前置知识:struct模块的.pack()方法
  前置知识:大端和小端。大端:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。
  在网络上,数据都要以大端发送。

reqtext=struck.pack("!H8sb5sb",1,"test.jpg",0,"octet",0)

!表示大端顺序
H表示占2 字节
s表示占1个字节,8s表示8字节。等效于ssssssss。"test.jpg"共8个字符。
b表示1字节。
5s同上。
In [1]: import struct

In [2]: struct.pack
Out[2]: 

In [3]: ?struct.pack
Docstring:
pack(fmt, v1, v2, ...) -> bytes

Return a bytes object containing the values v1, v2, ... packed according
to the format string fmt.  See help(struct) for more on format strings.
Type:      builtin_function_or_method

  现在直接发送请求报文,看服务器端的反应。

import socket
import struct

reqtext=struct.pack("!H8sb5sb",1,b"1234.png",0,b"octet",0)

udps=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server=("192.168.0.108",69)
udps.sendto(reqtext,server)

  ↑可以看到服务器端已经收到了报文的请求,但是一会就消失了,这是因为我们没有后续的应答导致。本来这里需要抓包分析,突然发现wireshark失灵。



  ↑原本使用正常的,突然系统自己进行了升级,出现了好多问题,win10真是一定要关闭掉破烂升级功能。
  后续几番搜索解决都没有用,包括右键cmd管理员运行,均提示无效。

net start npf

  最后无奈把wireshark及所有配属包全部卸载掉,然后重装,重启。


  ↑抓包。使用udp port == 69来过滤包,具体数据如上图。这里已经看到,请求报文已经发出去了,编程实现和预想是符合的。但是为什么只有一个包呢?因为限制了端口,所以其他包都被屏蔽了。下面要换一个过滤方式,来看服务器的回应是什么。

  ↑使用tftp来过滤。这里一共看到了3个包。其中:
  1、是我们发送的请求包。
  2、是服务器返回的一个数据包。数据块号为1。
  3、服务器发送的一个错误包。

import socket
import struct

g_blknum = 0

g_rf = None

reqtext = struct.pack("!H14sb5sb", 1, b"ipython.tar.gz", 0, b"octet", 0)
print(reqtext)
udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server = ("192.168.0.108", 69)
udps.sendto(reqtext, server)



while True:
        data = udps.recvfrom(1024)
        # print(len(data[0]))
        # print(data[0])
        # data是个元组,服务器返回的数据和服务器ip及端口

        # 把纯数据部分存入rdata
        rdata = data[0]
        # 把端口号存入serverport
        serverport = data[1][1]

        # print(rdata)
        # print(serverport)

        # 把返回数据的操作码和块号存入opblk,再拆包
        opblk = struct.unpack("!HH", rdata[0:4])
        opcode, block = opblk
        # print(opcode)
        # print(block)

        if opcode == 3:
                
                if block == 1:
                        g_rf = open("ipython.tar.gz", "wb")
                        g_rf.write(rdata[4:])
                        g_blknum += 1
                        ackt=struct.pack("!HH", 4, block)
                        print(ackt)
                        udps.sendto(ackt, ("192.168.0.108",serverport))       

                if (g_blknum+1) == block:
                        if len(data[0]) == 516:
                                g_rf.write(rdata[4:])
                                g_blknum += 1
                                ackt=struct.pack("!HH", 4, block)
                                # print(ackt)
                                udps.sendto(ackt, ("192.168.0.108",serverport))
                        else:
                                g_rf.write(rdata[4:]) 
                                ackt=struct.pack("!HH", 4, block)
                                udps.sendto(ackt, ("192.168.0.108",serverport))   
                                g_rf.close()
                                break


print(g_blknum)

  ↑上例是个简单的下载程序,但是在测试过程中,通过抓包发现还是会有服务器发送数据后,下载程序没有回复导致出错中止的问题。

import socket
import struct

# 全局变量计算包的数目
g_blknum = 0

# 全局变量保存文件对象
g_rf = None

# 创建一个请求报文字段
reqtext = struct.pack("!H14sb5sb", 1, b"ipython.tar.gz", 0, b"octet", 0)
print(reqtext)

# 创建UDP套接字
udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 构建服务器的数据元组,包含ip和端口
server = ("192.168.0.108", 69)

# 发送报文请求
udps.sendto(reqtext, server)


while True:

    # 接收服务器端返回的数据
    data = udps.recvfrom(1024)
    # print(len(data[0]))
    # print(data[0])
    # data是个元组,服务器返回的数据和服务器ip及端口

    # 把纯数据部分存入rdata
    rdata = data[0]
    # 把端口号存入serverport
    serverport = data[1][1]

    # print(rdata)
    # print(serverport)

    # 把返回数据的操作码和块号存入opblk,再拆包
    opblk = struct.unpack("!HH", rdata[0:4])
    opcode, block = opblk
    # print(opcode)
    print("reveive:")
    print(block)

    # 如果是数据包,则开始处理
    if opcode == 3:
        print("ipcode3")
        # 如果是第一块,则要创建文件,并写入
        if block == 1:
            print("block 1")
            g_rf = open("ipython.tar.gz", "wb")
            g_rf.write(rdata[4:])
            g_blknum += 1
            ackt = struct.pack("!HH", 4, block)
            print(ackt)
            udps.sendto(ackt, ("192.168.0.108", serverport))

        # 后续块,判断顺序是否是预期希望的,是则继续写入

        if (g_blknum+1) == block:
        #     print("block %d" % block)
            if len(data[0]) == 516:
                g_rf.write(rdata[4:])
                g_blknum += 1
                ackt = struct.pack("!HH", 4, block)
                print(ackt)
                print("ackbolk"+str(block))
                udps.sendto(ackt, ("192.168.0.108", serverport))
            else:
                #如果不是516字节,则是最后一个数据包,写完就关闭
                g_rf.write(rdata[4:])
                ackt = struct.pack("!HH", 4, block)
                udps.sendto(ackt, ("192.168.0.108", serverport))
                g_rf.close()
                print("Down load Success!")
                break
        #差错控制,如果发来的数据块是上次接收过的,那么直接确认数据包,不再写入
        elif g_blknum == block:
            ackt = struct.pack("!HH", 4, block)
            udps.sendto(ackt, ("192.168.0.108", serverport))
        else:
            print("g_blknum="+str(g_blknum))
            print("block="+str(block))

    if opcode == 5:
        print("Down load fialed")
        break

print(g_blknum)

  ↑附加了差错控制,貌似没有再发生中途出错问题。

  • 1-13 UDP广播

  udp有一种应用叫做广播。

li@li-System-Product-Name:~$ ifconfig
enp40s0: flags=4163  mtu 1500
        inet 192.168.1.113  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::b8d4:4d8d:b4bd:3b4d  prefixlen 64  scopeid 0x20
        ether 88:d7:f6:c7:41:25  txqueuelen 1000  (Ethernet)
        RX packets 24616  bytes 27148422 (27.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 19719  bytes 2421643 (2.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 1871  bytes 230274 (230.2 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1871  bytes 230274 (230.2 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

  首先查看linux的ip地址,为下步抓取数据用。

ip.addr==192.168.0.1 //过滤ip地址
data.len==8 //过滤data部分长度为8的数据包
data.data == 00:08:30:03:00:00:00:00 //过滤指定内容的数据包
udp.srcport == 10092 //过滤经过本机10092端口的udp数据包
udp.dstport == 80 //过滤目标机器10092端口的udp数据包
udp.port==10092 //过滤本机或目标机器10092端口的数据包
udp.length == 20 //过滤指定长度的

  wireshark的过滤规则

import socket
import sys

dest=("",7788)

s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#设置套接字以发送广播
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)

s.sendto(b"hi",dest)

  ↑可以看到广播成功发送

  • 1-14 tcp服务器代码编写服务器

In [1]: import  socket
   ...: 
   ...: 
   ...: sTCP=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   ...: 

In [2]: ?sTCP.accept
Signature: sTCP.accept()
Docstring:
accept() -> (socket object, address info)

Wait for an incoming connection.  Return a new socket
representing the connection, and the address of the client.
For IP sockets, the address info is a pair (hostaddr, port).
File:      /usr/lib/python3.6/socket.py
Type:      method
import  socket

#创建一个tcp套接字
sTCP=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
addr=("",8899)
sTCP.bind(addr)

#最多可以同时5个
sTCP.listen(5)

调用accept(),返回一个新套接字,和一个地址元组
sockobj,addrinfo=sTCP.accept()

data=sockobj.recv(1024)
print(sockobj)
print(addrinfo)
print(data)

sockobj.close()
sTCP.close()

  ↑编写了一个简单的tcp服务,客户端使用网络调试助手。查看端口是否建立可以使用如下命令:

li@li-System-Product-Name:~$ netstat -an | grep 8899

  ↑注意这里程序打开以后,默认识别的网卡地址一定要和服务器在同一网段,出现识别错误的情况一定要禁用其他网卡,否则会连接错误。

li@li-System-Product-Name:~/Documents$ cd /home/li/Documents ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /usr/bin/python3 /home/li/.vscode/extensions/ms-python.python-2019.8.30787/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 44557 /home/li/Documents/1.py 

('192.168.1.140', 51387)
b'312312312312312313'

  小结:
  1、socket创建一个套接字
  2、bind绑定ip和port
  3、listen使套接字变为被动链接
  4、accept等待客户端连接
  5、recv/send接收发送数据

  • 1-15 简单tcp客户端编写

from socket import *

cTCP=socket(AF_INET,SOCK_STREAM)
#服务器的ip和端口,这里和网络调试助手里的设置要相同。
cAddr=("192.168.0.108",8080)
#连接服务器
cTCP.connect(cAddr)

sData=b"im tcp client"
#发送中文要编码
sData1=bytes("哈哈哈哈".encode("gb2312"))
#发送不需要地址,因为已经连接好了服务器
#UDP发送数据因为没有之前的连接,所以需要每次发送填写接收方地址。
cTCP.send(sData)
cTCP.send(sData1)

rData=cTCP.recv(1024)
print(rData)

cTCP.close()
li@li-ThinkPad-T420s:~/Desktop/py$ cd /home/li/Desktop/py ; env PYTHONIOENCODING=UTF-8 PYTHONUNBUFFERED=1 /usr/bin/python3 /home/li/.vscode/extensions/ms-python.python-2019.8.30787/pythonFiles/ptvsd_launcher.py --default --client --host localhost --port 44409 /home/li/Desktop/py/ceshi.py 
b'fasgdsfgsdgsdg'

  使用网络调试助手测试成功

  • 1-16 使用tcp写聊天程序


你可能感兴趣的:(02Python学习笔记之二.十【网络编程初步】2019-08-26)