网络编程一

socket简介

1.本地的进程间通信(IPC)有很多种方式,例如

队列
同步(互斥锁、条件变量等)

以上通信方式都是在一台机器上不同进程之间的通信方式,那么问题来了网络中进程之间如何通信?

2. 网络中进程之间如何通信

首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。

这样利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互

3. 什么是socket

socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的例如我们每天浏览网页、QQ 聊天、收发 email 等等

4. 创建socket

在 Python 中 使用socket 模块的函数 socket 就可以完成:

socket.socket(AddressFamily, Type)

说明:

函数 socket.socket 创建一个 socket,返回该 socket 的描述符,该函数带有两个参数:

Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者    SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

创建一个tcp socket(tcp套接字)

import socket
#创建套接字对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket Created'

创建一个udp socket(udp套接字)

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print 'Socket Created'

tcp服务器

如同上面的电话机过程一样,在程序中,如果想要完成一个tcp服务器的功能,需要的流程如下:

socket创建一个套接字
bind绑定ip和port
listen使套接字变为可以被动链接
accept等待客户端的链接
recv/send接收发送数据

一个很简单的tcp服务器如下:

#coding=utf-8
from socket import *

# 创建socket
tcpSerSocket = socket(AF_INET, SOCK_STREAM)
# 绑定本地信息
address = ('', 7788)
tcpSerSocket.bind(address)

# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcpSerSocket.listen(5)

# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务器
# newSocket用来为这个客户端服务
# tcpSerSocket就可以省下来专门等待其他新客户端的链接
newSocket, clientAddr = tcpSerSocket.accept()

# 接收对方发送过来的数据,最大接收1024个字节
recvData = newSocket.recv(1024)
print '接收到的数据为:',recvData

# 发送一些数据到客户端
newSocket.send("thank you !")
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
newSocket.close()
# 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
tcpSerSocket.close()

tcp客户端

tcp客户端,并不是像之前一个段子:一个顾客去饭馆吃饭,这个顾客要点菜,就问服务员咱们饭店有客户端么,然后这个服务员非常客气的说道:先生 我们饭店不用客户端,我们直接送到您的餐桌上如果,不学习网络的知识是不是 说不定也会发生那样的笑话 ,哈哈。所谓的服务器端:就是提供服务的一方,而客户端,就是需要被服务的一方

tcp客户端构建流程

tcp的客户端要比服务器端简单很多,如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多

示例代码:

#coding=utf-8
from socket import *

# 创建socket
tcpClientSocket = socket(AF_INET, SOCK_STREAM)
# 链接服务器
serAddr = ('192.168.1.102', 7788)
tcpClientSocket.connect(serAddr)

# 提示用户输入数据
sendData = raw_input("请输入要发送的数据:")
tcpClientSocket.send(sendData)

# 接收对方发送过来的数据,最大接收1024个字节
recvData = tcpClientSocket.recv(1024)
print '接收到的数据为:',recvData
# 关闭套接字
tcpClientSocket.close()

应用:模拟QQ聊天

客户端参考代码

#coding=utf-8
from socket import *

# 创建socket
tcpClientSocket = socket(AF_INET, SOCK_STREAM)

# 链接服务器
serAddr = ('192.168.1.102', 7788)
tcpClientSocket.connect(serAddr)

while True:
    # 提示用户输入数据
    sendData = raw_input("send:")
    if len(sendData)>0:
       tcpClientSocket.send(sendData)
    else:
       break
    # 接收对方发送过来的数据,最大接收1024个字节
    recvData = tcpClientSocket.recv(1024)
    print 'recv:',recvData

# 关闭套接字
tcpClientSocket.close()

服务器端参考代码

#coding=utf-8
from socket import *

# 创建socket
tcpSerSocket = socket(AF_INET, SOCK_STREAM)

# 绑定本地信息
address = ('', 7788)
tcpSerSocket.bind(address)

# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcpSerSocket.listen(5)

while True:
    # 如果有新的客户端来链接服务器,那么就产生一个新的的套接字专门为这个客户端服务器
    # newSocket用来为这个客户端服务,clientAddr是客户端的ip地址。
    # 等待其他新客户端的链接是通过死循环实现。如果这里没有新的客户端连接则会阻塞线程。
    newSocket, clientAddr = tcpSerSocket.accept()

    while True:
        # 接收对方发送过来的数据,最大接收1024个字节。
        recvData = newSocket.recv(1024)
        # 如果接收的数据的长度为0,则意味着客户端关闭了链接
        if len(recvData)>0:
           print 'recv:',recvData
        else:
           break

        # 发送一些数据到客户端
        sendData = raw_input("send:")
        newSocket.send(sendData)

    # 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
    newSocket.close()
# 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
tcpSerSocket.close()

案例:人脸识别服务端与客户端

服务器端参考代码

# coding=utf-8
"""输入一张图片经过检测、特征提取环节然后匹配输出标签和距离"""
import argparse
import sys,os
import time
import cv2
import face
from scipy import misc 
from socket import *
import threading
from Queue import Queue

mess_dic = {}
def get_message(q1,q2,tcpSerSocket):
   #HOST ='192.168.1.189'
   #PORT = 8080  

   while True:
        #为每个新连接的客户创建新的socket,如果没有新的客户端连接就会阻塞线程,通过死循环实现。
        print("~~~~~~~~~~~~~等待客户端链接~~~~~~~~~~~~~~")
        newSocket, clientAddr = tcpSerSocket.accept()

       while True:      
            recvData = newSocket.recv(1024)
            print("~~~~~~~~~~~~~客户端链接成功~~~~~~~~~~~~~~")
            if recvData > 0: 
               print("~~~~~~~~~~~~~已收到客户端数据~~~~~~~~~~")
               #收到错误数据的异常处理
               try :
                   image = misc.imread(recvData)  
               except :
                   print "提示:数据发生异常!"
                   break
               else:  
                   q1.put(image)
                   print("~~~~~~~~~~~~~数据已经加入队列q1~~~~~~~~~~")
            else:
               print("~~~~~~~~~~~~~未收到客户端数据~~~~~~~~~~")
            if q2.empty():
               time.sleep(1)
            else:
               value = q2.get()
               print("~~~~~~~~~~~~~得到输出检测结果~~~~~~~~~~~~~~")
               newSocket.send(str(value))

        #由于异常退出while循环后需要关闭该套接字,才能重新建立显得连接
        newSocket.close()
    #同理,被动接听的套接字最后(关闭服务器时)也需要关闭
    tcpSerSocket.close()

def main(): 
   #创建两个队列   
   q1 = Queue()
   q2 = Queue()

   #创建socket(被动接听套接字)
   tcpSerSocket = socket(AF_INET, SOCK_STREAM)
   address = ('', 8080)
   tcpSerSocket.bind(address)
   tcpSerSocket.listen(5)
   #把人脸识别模型预先载入内存
   face_recognition = face.Recognition()

   #接受信息线程
   get_thread = threading.Thread(target=get_message,args=(q1,q2,tcpSerSocket,))   
   #启动线程
   get_thread.start()   

   #主线程进行人脸识别
   while True:
       if q1.empty():
          print "队列q1中没有数据"
          time.sleep(1)
       else:
          value = q1.get() 
          print "从队列q1中取出数据"          
          faces = face_recognition.identify(value)  

          if faces:   
             for one_face in faces:
                 face_bb = one_face.bounding_box.astype(int)
                 cv2.rectangle(value, (int(face_bb[0]),int(face_bb[1])),(int(face_bb[2]),int(face_bb[3])),(255,0,0))                    

                 if one_face.dist < 0.5:
                    #cv2.putText(value, str(one_face.dist),(face_bb[0], face_bb[3]),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255,0),thickness=1, lineType=1)
                    #misc.imshow(value)              
                    mess_dic = {}
                    mess_dic[one_face.label] = one_face.embedding    
                    q2.put(mess_dic)  
                    print "检测数据已经放入队列q2"                                              
                 else:  
                    print "警告:陌生人!"
           else:
               print "提示:未检测到人脸!"              
    get_thread.join()   

if __name__ == '__main__':
     main()

客户端参考代码

#coding=utf-8
from socket import *
import os,time
import threading
from Queue import Queue

# 创建socket
tcpClientSocket = socket(AF_INET, SOCK_STREAM)

# 链接服务器
serAddr = ('192.168.1.162', 8080)
tcpClientSocket.connect(serAddr)

f = open("/home/ubuntu/facenet/contributed/cbir/image.txt")
#辅助线程接收来自服务器的数据
def get_message(queue):
    while True:
         print  "等待接收服务器返回的数据"
         recv_data = tcpClientSocket.recv(1024)   
         if len(recv_data)>0:
            print  "收到服务器返回的数据"
            print 'recv_data:',recv_data
            time.sleep(1)
    tcpClientSocket.close()

##主线程发送数据
def main():
   queue = Queue()
   get_thread = threading.Thread(target=get_message,args=(queue,))
   get_thread.start()    

   while True: 
        print ("~~~~~~~~~~~向服务器发送数据~~~~~~~~~~~~~")
        image = f.readline()
        image = image.strip('\n')
        if len(image)>0:
           tcpClientSocket.send(image)
           print ("~~~~~~~~~~~~~发送数据成功~~~~~~~~~~~~~~~")         
           time.sleep(1)
        else:
           time.sleep(1)

if __name__ == '__main__':
   main()   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值