标签:ima inpu 用户 缓冲 网络 os模块 编码 进程 name

socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)


socket.AF_UNIX unix本机进程间通信 socket.AF_INET IPV4 socket.AF_INET6  IPV6socket.SOCK_STREAM  #for tcpsocket.SOCK_DGRAM   #for udp socket.SOCK_RAW     #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。socket.SOCK_RDM  #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。socket.SOCK_SEQPACKET #废弃了之前我们只是介绍了soket的概念和一些逻辑图表,下面我们来看看,socket的客户端和服务端到底是怎么用的?
2.1.1 客户端代码逻辑图

2.1.2 客户端代码
| 1 2 3 4 5 6 7 8 9 10 | importsocket   #导入socket模块client =socket.socket()  #创建socket实例client.connect(("localhost",6969))  #建立连接send_data ="hello word!"#发送的字符串send_data =send_data.encode() #因为发送是bytes类型,所以这边先转码成bytes类型client.send(send_data)  #发送数据,这边发送的是字节类型,也就是bytes类型data =client.recv(1024)  #接收服务端的数据,这边设置接收1024字节  1kb=1024字节print("server rece:",data.decode())client.close()   #关闭与服务端的链接 | 
2.2.1 服务端代码逻辑图

2.2.2 服务端代码
| 1 2 3 4 5 6 7 8 9 10 11 12 | importsocketsever =socket.socket()  #创建服务端实例sever.bind(("localhost",6969))   #绑定客户端ip和端口sever.listen()   #监听端口print("我在电话了....")conn,addr =sever.accept()   #接收客户端,并且返回连接标志位(conn)实例,和对方的ip地址(addr)data =conn.recv(1024)   #接收客户端发过来的数据,接收的也是bytes类型的数据print("我的电话来了")print("client data:",data.decode())conn.send(data.upper())  #发送数据至服务端,注意这边发送的也是字节类型,是bytes类型sever.close()  #关闭服务端 | 
本篇博客讲一下,如果socket客户端断了,另外的客户端怎么接入服务端,还有模拟ssh的链接等。
因为在python 3中只能接受bytes类型的数据,bytes类型只能接受ASCII码里面的数据类型。因为bytes类型是一个ASCII 0-255的数字组合。所以在客户端向服务端传中文时一定要先转成bytes类型,也就是encode(),接收方需要解码,也就是decode()才能识别中文。
①客户端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | importsocketclient =socket.socket()client.connect(("localhost",6969))msg ="小高最帅了"client.send(msg.encode())  #传中文至服务端,需要先编码server_data  =client.recv(1024)print("recv:",server_data)   #未解码print("recv:",server_data.decode())   #解码client.close()#输出recv: b‘\xe5\xb0\x8f\xe9\xab\x98\xe6\x9c\x80\xe5\xb8\x85\xe4\xba\x86‘#bytes类型recv: 小高最帅了   #字符串 | 
②服务端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | importsocketsever =socket.socket()sever.bind(("127.0.0.1",6969))  #绑定ip地址和端口sever.listen()   #监听conn,address =sever.accept()   #获取接收实例和ip地址print("电话来了")client_data =conn.recv(1024)   #接收客户端数据print("recv:",client_data)print("recv:",client_data.decode())conn.send(client_data)   #发送给客户端sever.close()#输出电话来了recv: b‘\xe5\xb0\x8f\xe9\xab\x98\xe6\x9c\x80\xe5\xb8\x85\xe4\xba\x86‘#bytes类型recv: 小高最帅了   #解码后的结果 | 
注意了:所有的数据发送和接收都用bytes类型就可以了,省的有什么异常情况。
上面的代码只能客户端只能发送一次,服务端接收一次,就这么结束了,感觉很不爽,那怎么实现客户端发送多次,服务端接收多次呐?
①客户端
说明:客户端在发送处设置死循环(while True),实现重复发送。
| 1 2 3 4 5 6 7 8 9 10 11 12 | importsocketclient =socket.socket()client.connect(("localhost",6969))whileTrue:    #进入死循环,设置无限次发送    msg =input(">>>:")    client.send(msg.encode())    data  =client.recv(1024)    print("recv:",data.decode())client.close() | 
②服务端
说明:服务端在接收时,设置死循环,实现重复接收。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | importsocketsever =socket.socket()sever.bind(("127.0.0.1",6969))sever.listen()conn,address =sever.accept()   #接收连接实例print("电话来了")whileTrue:   #设置死循环,接收多次    data =conn.recv(1024)    print("recv:",data.decode())    conn.send(data)sever.close() | 
注:这边注意了,在服务端,while True千万不能写在conn,address = sever.accept()前面,这个是为什么呢?因为客户端跟服务端只能实现建立一个连接,如果你把while True放在前面,则服务端接收数据后,又要重新建立一个新的等待连接,这样,客户端和服务端都会卡主。
服务端的代码如下:

表现现象:


说明:我们在客户端一起链接服务端,我们都知道,一个服务端只能跟一个客户端进行链接通信,那如果说,我这个正在通信的客户端断开跟服务端的通信,那其他的某个客户端就能跟客户端正常通信了,这个实验一定要在Linux服务器上去完成,因为在Windows上就是只要客户端一断开,服务端就断开了。
跟上面一样,客户端的代码没有变,我们现在来变一下服务端的代码:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | importsocketsever =socket.socket()sever.bind(("127.0.0.1",6969))sever.listen()whileTrue: #在建立连接之前加一个死循环    conn,address =sever.accept()    print("电话来了")  count =0#加一个计数器    whileTrue:        data =conn.recv(1024)     ifnotdata:break#这边如果接受客户端数据为空,则重新建立连接        print("recv:",data.decode())        conn.send(data)     count +=1sever.close() | 
注意:上面if not data:break这段代码不写的后果是:当客户端断开链接时,服务端进入死循环,不断接收客户端的空数据。
现象如图:
①客户端

②服务端

说明:我们之前演示都是客户端输入内容,服务端给出相应,那客户端输入的是空的话,服务端会有什么反映呐?
客户端代码如图:

服务端代码跟上面的一样,执行结果如下:
客户端:

服务端:

原因是:客户端输入的为空,服务端还一直以为客户端在send,然后都卡主了。
那代码怎么改进呢?代码改进如下:
客户端代码:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | importsocketclient =socket.socket()client.connect(("localhost",6969))whileTrue:    msg =input(">>>:")    iflen(msg) ==0:continue#这边判断输入的字符是否为空,为空就跳过    client.send(msg.encode())    data  =client.recv(1024)    print("recv:",data.decode())client.close() | 
表现现象:
客户端:

服务端:

说明:以下代码,是在Linux下环境,而且还是python2.7的环境,如果是python 3的话,需要编码和解码。
①客户端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #! /usr/bin/env python# -*- coding:utf-8 -*-importsocketclient =socket.socket()client.connect(("localhost",6969))whileTrue:    msg =raw_input(">>>:")    iflen(msg) ==0:continue    client.send(msg)    data  =client.recv(1024)    print(data)client.close() | 
②服务端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #! /usr/bin/env python# -*- coding:utf-8 -*-importsocket,os   #导入os模块sever =socket.socket()sever.bind(("127.0.0.1",6969))sever.listen(5)  #最大允许有多少个链接whileTrue:    conn,address =sever.accept()    print("电话来了")    count =0    whileTrue:        data =conn.recv(1024)        ifnotdata:break        res =os.popen(data).read()   #调用linux命令        conn.send(res)   #执行的命令返回值sever.close() | 
注:conn.send(res)这边如果需要发送全部的话,需要conn.sendall(res)
①客户端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | importsocketclient =socket.socket()client.connect(("localhost",6969))whileTrue:    msg =input(">>>:")    iflen(msg) ==0:continue    client.send(msg.encode())    data  =client.recv(1024000)   #这边设置的大一点,防止文件的内容接收不到    with open("test_put","wb") as test_put_file:   #把下载下来的内容写入到文件中        test_put_file.write(data)client.close() | 
②服务端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | importsocketsever =socket.socket()sever.bind(("127.0.0.1",6969))sever.listen()conn,address =sever.accept()print("电话来了")whileTrue:    data =conn.recv(1024)    ifnotdata:        print("数据为空")        break    with open("test","rb") as test_file:        all_data_bytes =test_file.read()   #读取需要下载的文件,发送给客户端    conn.sendall(all_data_bytes)sever.close() | 
注意:这边客户端的接收时有限制的,如果超出了客户端的限制,客户端只接收自己的一部分,而剩余的会在还是在缓冲去,下一次服务端再send的时候,不会发新数据,先把缓冲区剩下的数据发送到客户端。
如图:

标签:ima inpu 用户 缓冲 网络 os模块 编码 进程 name
原文地址:http://www.cnblogs.com/luoahong/p/7208471.html