60

socket封装

分类

一般讲的socekt指的是基于网络间的socket,实际上,socket并不是只用在网络间的。

  • Unix domain Socket

    Unix domain socket , 其实从解释当中就能够看出,它是一种进程间通信的一种方式。支持域间TCPUDP, 可信赖的UDP等几种协议,当然主要适用于unix的进程间通信。

  • Network Socket
    Network Socket , 这种socket就是常见的网络间通信的socket,它是属于在OSI层中位于TCPUDP上层的一种API,通过它,可以创建TCPUDP的通信。

Python Socket

python将socket打包,在2和3中还是有很大的区别,下面的例子将以python3.5例。

# TCP 服务器, 特定数目的连接
from SocketServer import StreamRequestHandler, TCPServer

class EchoHandler(StreamRequestHandler):
    def handle(self):
        print('Got connection from', self.client_address)
        for line in self.rfile:
            self.wfile.write(line)

if __name__ == '__main__':
    from threading import Thread
    NETWORKS = 100
    serv = TCPServer(('', 20000), EchoHandler)
    for n in range(NETWORKS):
        t = Thread(target=serv.serve_forever)
        t.daemon = True
        t.start()
    serv.serve_forever()            

# UDP 服务器
from socket import socket, AF_INET, SOCK_DGRAM
import time

def time_server(address):
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.bind(address)
    while True:
        msg, addr = socke.recvfrom(8192)
        print('Got message from', address)
        resp = time.ctime()
        sock.sendto(resp.encode('ascii'), address)

if __name__ == "__main__":
    time_server(('', 20000))

NodeJS Socket

TCP 客户端和服务器, 实际上这个并算不上socket,因为node其实已经将它进行了封装,TCP--net, UDP--dram, http, https等等封装包。

// TCP server

var net = require('net');

var server = net.createServer(function (socket) {
    socket.on('data', function (data) {
        socket.write("hello TCP client \n");
    });

    socket.on('end', function () {
        console.log("TCP client has unconnected \n");
    });

    socket.write("hello world \n");
});

server.listen(20000, function () {
    console.log('server has served \n');
});

// TCP client

var net = require('net');

var client = net.connect({port: 20000}, function () {
    console.log('client connected \n');
    client.write('world \r\n');
});

client.on('data', function (data) {
    console.log(data.toString());
    client.end();
});

client.on('end', function () {
    console.log('client unconnected \n');
});

UDP 客户端和服务器

// UDP server

var dgram = require('dgram');

var server = dgram.createSocket('udp4');

server.on("message", function (msg, rinfo) {
    console.log('server got:' + msg + "from" + 
        rinfo.address + ":" + rinfo.port + "\n");
    console.log(msg, rinfo);
});

server.on("listening", function () {
    var address = server.address();
    console.log("server listening" 
        + address.address
        + ":" 
        + address.port
    );
});

server.bind(20000);

// UDP client
var dgram = require('dgram');

var message = new Buffer("client");
var client = dgram.createSocket("udp4");
client.send(
    message, 0, message.length, 20000, "localhost",
    function (err, bytes) {
            client.close();
    }
);

Php Socket

最近做了一个 php 中间件作为数据的中转,可以接收多个用户进行连接。并且和客户端建立 websocket 连接。

// 代码中的 Socket 是我自己封装的类,将其替换成正常的 socket_create(),其他的也类似
//其中的一些函数是用来处理websocket连接的,以及数据的处理。可以忽略

set_time_limit(0);
error_reporting(E_WARNING);

define('UDP_IP', '127.0.0.1');
define('UDP_PORT', 20001);
define('UDP_RMT_PORT', 9102);
define('WS_PORT', 20000);
define('WS_IP', '127.0.0.1');

$ws = new Socket(WS_IP, 9102, 'TCP');
$udp = new Socket(UDP_IP, 9102, 'UDP');

if ($ws->skt == false || $udp->skt == false) {
        echo 'socket create error: ' . socket_strerror(socket_last_error()) . "\n";
        exit(0);
}

if ($ws->bind(WS_IP, WS_PORT) == false || $udp->bind(UDP_IP, UDP_PORT) == false) {
        echo "socket bind error:" . socket_strerror(socket_last_error()) . "\n";
        exit(0);
}

if ($ws->listen() === false) {
        echo "socket listen error" . socket_strerror(socket_last_error()) . "\n";
        exit(0);
}

$write = $except = NULL;
$clients = array($ws->skt);
while (true) {
        $changed = $clients;
        socket_select($changed, $write, $except, 0);
        /**
         *   This section is to check if the ws_socket which connected with client socket
         * has new client socket connected.
         *   If it is, then push the new client socket to
         * the $clients array. And then call getHandShake() to shake hands with the web
         * socket. Lastly, remove the local socket from $changed array.
         *   If it is not, that means that the local socket has not incoming socket.
         */
  if (in_array($ws->skt, $changed)) {
            $clt_socket = socket_accept($ws->skt);
            array_push($clients, $clt_socket);
            $clt_sk_header = Socket::read($clt_socket);
            Socket::getHandShake($clt_sk_header, $clt_socket, WS_IP, WS_PORT);
            $key = array_search($ws->skt, $changed);
            unset($changed[$key]);
  }
        /**
         *   This section is to loop all socket that had connected the local socket $ws->skt
         * and then receive message from all clients .
         *   Then, unmask them to make it is easy to transport the data to C++ socket which
         * is in the port 9102 .
         *   Lastly, check if socket is unconnected. If it is, then remove it.
         */

foreach ($changed as $changed_socket) {
            echo "now it is receiving data from user $changed_socket \n";
    while (($clt_data = Socket::recv($changed_socket)) != false) {
                $clt_data = Socket::unMask($clt_data);
                $udp->sendTo($clt_data);
                break 2;
    }
     $dis_cnt_flag = Socket::read($changed_socket);
     if ($dis_cnt_flag === false) {
                $fd_key = array_search($changed_socket, $clients);
                unset($clients[$fd_key]);
     }
}
        /**
         *   This section is to receive the message from C++ socket,
         * and the timeout is set to 2 sec. If receiving message, it
         * would transport message to every client.
         */
$sv_data = $udp->revFrom();
if ($sv_data != false) {
            $sv_data = Socket::Mask($sv_data);
            foreach ($clients as $clt) {
                Socket::write($clt, $sv_data);
            }
            echo "\n THE SERVER DATA : $sv_data \n";
}
}

以上就是我熟悉的三种语言的 TCP/UDP 服务的写法,和socket有些联系。其实最主要的还是最后的php。它算是我从底层开始写的socket。当然,socketpython中也有类似于php的机制,当然我也更喜欢python的这种方式,形式上有美感。

# ! /usr/bin/env python
# python3.3

from socket import socket, AF_INET, SOCK_STREAM
from time import ctime

HOST = ''
PORT = 20000
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcp_sv = socket(AF_INET, SOCK_STREAM)
tcp_sv.bind(ADDR)
tcp_sv.listen(5)

while True:
        print "waiting for connection \n"
        tcp_clt, addr = tcp_skt.accept()
        print "...connected from : ", addr

        while True:
                data = tcp_clt.recv(BUFSIZ)
                if not data:
                    break
                tcp_clt.send('[%s] %s' % (ctime(), data))
        tcp_clt.close()
tcp_sv.close()                            

以上就是socket的几种示例

编码-2