Maison  >  Article  >  développement back-end  >  Comment créer une salle de discussion simple à l'aide de PHP Websocket

Comment créer une salle de discussion simple à l'aide de PHP Websocket

伊谢尔伦
伊谢尔伦original
2017-05-24 11:33:252464parcourir

Le

socket est la couche d'abstraction logicielle intermédiaire qui communique entre la couche application et la suite de protocoles TCP/IP. Il s'agit d'un ensemble d'interfaces. En mode conception, Socket est en fait un mode façade, qui cache la famille complexe de protocoles TCP/IP derrière l'interface Socket. Pour les utilisateurs, un ensemble d'interfaces simples constitue tout, permettant à Socket d'organiser les données pour se conformer au protocole spécifié. Dans le chapitre précédent, nous avons parlé de la différence entre socket et http Pour comprendre socket, vous devez d'abord comprendre la différence entre http et tcp En termes simples, l'un est une chaîne courte, l'autre est une longue. chaîne, et l'autre est d'extraire les données du serveur, l'une est que le serveur peut activement pousser les données. Les connexions HTTP sont divisées en connexions courtes et connexions longues. Les connexions courtes peuvent généralement être implémentées à l'aide d'Ajax, et les connexions longues sont des websockets. Les connexions courtes sont relativement simples à mettre en œuvre, mais consomment trop de ressources. Websocket est efficace mais présente quelques problèmes de compatibilité. Websocket est une ressource HTML5.

Introduction au processus de création d'une salle de discussion simple avec php websocket

Les salles de discussion php étaient autrefois implémentées via ajax et PHP aujourd'hui. Jetons un coup d'œil à un exemple pratique de la technologie WebSocket dans une salle de discussion PHP.

1 Le client front-end

Comment fonctionne le fichier front-end. envoyer des informations au serveur back-end ? Des recherches ultérieures ont révélé qu'il utilise la technologie js WebSocket, voici les opérations courantes de js WebSocket :

Le code est le suivant :

var socket = new WebSocket('ws://localhost:8080');     
    // 打开Socket     
    socket.onopen = function(event) {     
    }    
    // 发送一个初始化消息    
     socket.send('I am the client and I\'m listening!');     
    // 监听消息    
     socket.onmessage = function(event) {     
        console.log('Client received a message',event);     
      };  //phpfensi.com    
    // 监听Socket的关闭    
      socket.onclose = function(event) {     
        console.log('Client notified socket has closed',event);     
      };     
      // 关闭Socket....     
    socket.close()     
   socket.onerror = function(evt){console.log(“WebSocketError!”);};

Explication : La première ligne enverra une demande d'établissement de liaison au serveur spécifié. Si le serveur Si un en-tête http valide est renvoyé, la négociation réussit et le message envoyé par le serveur peut être traité en écoutant l'événement onmessage. Il existe de nombreux autres événements qui peuvent être surveillés, voir l'URL précédente.

2. Le serveur d'arrière-plan

Le processus effectué par le serveur est grossièrement :

a. Suspendre un processus de socket En attente de connexion.

b. Une fois la connexion de socket établie, parcourez le tableau de sockets

c. S'il n'y a pas de prise de contact, effectuez une opération de prise de contact. S'il y a une prise de contact, recevez les données, analysez-les et. écrivez-le dans le tampon pour la sortie

L'exemple de code est le suivant :

public function start_server(){
  $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  //允许使用本地地址
  socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, TRUE);
  socket_bind($this->socket, $this->host, $this->port);
  //最多10个人连接,超过的客户端连接会返回WSAECONNREFUSED错误
  socket_listen($this->socket, $this->maxuser);
  while(TRUE) {
    $this->cycle = $this->accept;
    $this->cycle[] = $this->socket;
    //阻塞用,有新连接时才会结束
    socket_select($this->cycle, $write, $except, null);
    foreach ($this->cycle as $k => $v) {
      if($v === $this->socket) {
        if (($accept = socket_accept($v)) < 0) {
          continue;
        }
        //如果请求来自监听端口那个套接字,则创建一个新的套接字用于通信
        $this->add_accept($accept);
        continue;
      }
      $index = array_search($v, $this->accept);
      if ($index === NULL) {
        continue;
      }
      //没消息的socket就跳过
      if (!@socket_recv($v, $data, 1024, 0) || !$data) {
        $this->close($v);
        continue;
      }
      if (!$this->isHand[$index]) {
        $this->upgrade($v, $data, $index);
        if(!empty($this->function[&#39;add&#39;])) {
          call_user_func_array($this->function[&#39;add&#39;], array($this));
        }
        continue;
      }
      $data = $this->decode($data);
      if(!empty($this->function[&#39;send&#39;])) {
        call_user_func_array($this->function[&#39;send&#39;], array($data, $index, $this));
      }
    }
    sleep(1);
  }
}
//增加一个初次连接的用户
public function add_accept($accept){
  $this->accept[] = $accept;
  $index = array_keys($this->accept);
  $index = end($index);
  $this->isHand[$index] = FALSE;
}
//关闭一个连接
public function close($accept) {
  $index = array_search($accept, $this->accept);
  socket_close($accept);
  unset($this->accept[$index]);
  unset($this->isHand[$index]);
  if(!empty($this->function[&#39;close&#39;])) {
    call_user_func_array($this->function[&#39;close&#39;], array($this));
  }
}
//响应升级协议
public function upgrade($accept, $data, $index) {
  if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$data,$match)) {
    $key = base64_encode(sha1($match[1] . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;, true));
    $upgrade  = "HTTP/1.1 101 Switching Protocol\r\n" .
      "Upgrade: websocket\r\n" .
      "Connection: Upgrade\r\n" .
      "Sec-WebSocket-Accept: " . $key . "\r\n\r\n";  //必须以两个回车结尾
    socket_write($accept, $upgrade, strlen($upgrade));
    $this->isHand[$index] = TRUE;
  }
}

Explication : Il y a plusieurs points clés L'un est while(true) pour suspendre le processus, sinon le. le processus se terminera après l’avoir exécuté une fois. La seconde est l’utilisation des fonctions socket_select et socket_accept. Le troisième est la poignée de main lorsque le client fait la première demande.

Le processus suivant est très clair. Lorsqu'une nouvelle demande client arrive, utilisez socket_accept pour créer une ressource et ajoutez-la au pool de connexion $this->accept. Et définissez son étiquette isHand sur false, puis la prochaine fois qu'il effectuera un cycle (car $this->cycle[] = $this->socket;$this->cycle a changé, donc socket_select reviendra) Effectuez une négociation de mise à niveau. Alors attendez simplement ses nouveaux messages.

【Tutoriels associés recommandés】

1. "php.cn Dugu Jiujian (4) - Tutoriel vidéo PHP "

2. ensemble de tutoriels sur la programmation PHP de l'entrée à la maîtrise

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn