PHP가 소켓을 사용하여 HTTP 요청을 보내는 방법에 대한 자세한 설명

*文
풀어 주다: 2023-03-19 09:10:01
원래의
2139명이 탐색했습니다.

PHP 프로그래머라면 반드시 http 프로토콜을 접하게 될 것입니다. http 프로토콜을 깊이 이해해야만 프로그래밍 수준이 향상될 수 있습니다. 최근에 저는 PHP로 HTTP 프로그래밍을 배우면서 많은 것들이 갑자기 명확해졌고 많은 유익을 얻었습니다. 모든 사람과 공유하길 바랍니다. 이 문서는 특정 http 기반을 갖춘 개발자가 읽어야 합니다. 그것이 모두에게 도움이 되기를 바랍니다.

오늘 보여드릴 내용은 소켓을 사용하여 GET 및 POST 요청을 보내는 방법입니다.

일상적인 프로그래밍에서 저와 같은 많은 사람들이 대부분의 경우 브라우저를 사용하여 서버에 GET 및 POST 요청을 한다고 생각합니다. 그러면 다른 방법을 사용하여 GET 및 POST 요청을 할 수 있나요? 대답은 '예'여야 합니다. HTTP 프로토콜을 아는 사람은 요청을 제출하는 브라우저의 본질이 요청 정보를 서버에 보내는 것임을 알고 있습니다. 이 요청 정보는 요청 라인, 요청 헤더 및 요청 본문(선택 사항)으로 구성됩니다. 서버는 요청 정보를 기반으로 응답 정보를 반환합니다. 연결이 끊어졌습니다.

HTTP 요청의 형식은 다음과 같습니다.

<request-line>
<headers>
<blank line>
[<request-body>]
로그인 후 복사

HTTP 응답의 형식은 요청 형식과 매우 유사합니다.

<status-line>
<headers>
<blank line>
[<response-body>]
로그인 후 복사

HTTP의 원리를 사용하여 요청을 보낼 수 있으며 소켓을 사용하여 요청을 다시 고려할 수 있습니다. HTTP 요청을 보냅니다.

 Socket의 원래 영어 의미는 "구멍" 또는 "소켓"입니다. 일반적으로 "소켓"이라고도 하며 IP 주소와 포트를 설명하는 데 사용됩니다. 이는 통신 체인에 대한 핸들이며 서로 다른 가상 머신 또는 서로 다른 컴퓨터 간의 통신을 구현하는 데 사용할 수 있습니다. 인터넷상의 호스트는 일반적으로 여러 서비스 소프트웨어를 실행하고 동시에 여러 서비스를 제공합니다. 각 서비스는 소켓을 열고 포트에 바인딩됩니다. 다른 포트는 다른 서비스에 해당합니다. 이러한 관점에서 볼 때 실제로 소켓을 사용하여 원격 파일을 작동하는 것은 로컬 파일을 읽고 쓰는 것만큼 쉽습니다. 로컬 파일은 하드웨어를 통해 전송되고, 원격 파일은 네트워크 케이블을 통해 전송되는 것으로 생각하십시오.

따라서 요청을 보내는 것은 연결 설정으로 간주될 수 있습니다. -> 소켓 인터페이스 열기(fsockopen()) -> 요청 쓰기(fwrite()) -> 응답 읽기(fread() -> 닫기 더 이상 고민하지 않고 바로 코드로 넘어가겠습니다.

<?php 
interface Proto {
  // 连接url
  function conn($url);
  //发送get查询
  function get();
  // 发送post查询
  function post();
  // 关闭连接
  function close();
}
class Http implements Proto {
  const CRLF = "\r\n";
  protected $errno = -1;
  protected $errstr = &#39;&#39;;
  protected $response = &#39;&#39;;
  protected $url = null;
  protected $version = &#39;HTTP/1.1&#39;;
  protected $fh = null;
  protected $line = array();
  protected $header = array();
  protected $body = array();
  public function __construct($url) {
    $this->conn($url);
    $this->setHeader(&#39;Host: &#39; . $this->url[&#39;host&#39;]);
  }
  // 此方法负责写请求行
  protected function setLine($method) {
    $this->line[0] = $method . &#39; &#39; . $this->url[&#39;path&#39;] . &#39;?&#39; .$this->url[&#39;query&#39;] . &#39; &#39;. $this->version;
  }
  // 此方法负责写头信息
  public function setHeader($headerline) {
    $this->header[] = $headerline; 
  }
  // 此方法负责写主体信息
  protected function setBody($body) {
     $this->body[] = http_build_query($body);
  }
  // 连接url
  public function conn($url) {
    $this->url = parse_url($url);
    // 判断端口
    if(!isset($this->url[&#39;port&#39;])) {
      $this->url[&#39;port&#39;] = 80;
    }
    // 判断query
    if(!isset($this->url[&#39;query&#39;])) {
      $this->url[&#39;query&#39;] = &#39;&#39;;
    }
    $this->fh = fsockopen($this->url[&#39;host&#39;],$this->url[&#39;port&#39;],$this->errno,$this->errstr,3);
  }
  //构造get请求的数据
  public function get() {
    $this->setLine(&#39;GET&#39;);
    $this->request();
    return $this->response;
  }
  // 构造post查询的数据
  public function post($body = array()) {   
    $this->setLine(&#39;POST&#39;);
    // 设计content-type
    $this->setHeader(&#39;Content-type: application/x-www-form-urlencoded&#39;);
    // 设计主体信息,比GET不一样的地方
    $this->setBody($body);
    // 计算content-length
    $this->setHeader(&#39;Content-length: &#39; . strlen($this->body[0]));
    $this->request();
    return $this->response;
  }
  // 真正请求
  public function request() {
    // 把请求行,头信息,实体信息 放在一个数组里,便于拼接
    $req = array_merge($this->line,$this->header,array(&#39;&#39;),$this->body,array(&#39;&#39;));
    //print_r($req);
    $req = implode(self::CRLF,$req); 
    //echo $req; exit;
    fwrite($this->fh,$req);
    while(!feof($this->fh)) {
      $this->response .= fread($this->fh,1024);
    }
    $this->close(); // 关闭连接
  }
  // 关闭连接
  public function close() {
    fclose($this->fh);
  }
}
로그인 후 복사

이 클래스를 사용하여 간단한 GET 요청을 보냅니다.

<?php
//记得引用Http类
$url="http://home.***.net/u/DeanChopper/";
$http=new Http($url);
$response=$http->get();
print_r($response);
로그인 후 복사

반환 값은 정보이며 응답 정보를 추가로 처리할 수 있습니다.

다음 구체적인 예를 살펴보겠습니다

<?php
/**
 * 使用PHP Socket 编程模拟Http post和get请求
 * @author koma
 */
class Http{
  private $sp = "\r\n"; //这里必须要写成双引号
  private $protocol = &#39;HTTP/1.1&#39;;
  private $requestLine = "";
  private $requestHeader = "";
  private $requestBody = "";
  private $requestInfo = "";
  private $fp = null;
  private $urlinfo = null;
  private $header = array();
  private $body = "";
  private $responseInfo = "";
  private static $http = null; //Http对象单例
   
  private function __construct() {}
   
  public static function create() {
    if ( self::$http === null ) { 
      self::$http = new Http();
    }
    return self::$http;
  }
   
  public function init($url) {
    $this->parseurl($url);
    $this->header[&#39;Host&#39;] = $this->urlinfo[&#39;host&#39;];
    return $this;
  }
   
  public function get($header = array()) {
    $this->header = array_merge($this->header, $header);
    return $this->request(&#39;GET&#39;);
  }
   
  public function post($header = array(), $body = array()) {
    $this->header = array_merge($this->header, $header);
    if ( !empty($body) ) {
      $this->body = http_build_query($body);
      $this->header[&#39;Content-Type&#39;] = &#39;application/x-www-form-urlencoded&#39;;
      $this->header[&#39;Content-Length&#39;] = strlen($this->body);
    }
    return $this->request(&#39;POST&#39;);
  }
   
  private function request($method) {
    $header = "";
    $this->requestLine = $method.&#39; &#39;.$this->urlinfo[&#39;path&#39;].&#39;?&#39;.$this->urlinfo[&#39;query&#39;].&#39; &#39;.$this->protocol;
    foreach ( $this->header as $key => $value ) {
      $header .= $header == "" ? $key.&#39;:&#39;.$value : $this->sp.$key.&#39;:&#39;.$value;
    }
    $this->requestHeader = $header.$this->sp.$this->sp;
    $this->requestInfo = $this->requestLine.$this->sp.$this->requestHeader;
    if ( $this->body != "" ) {
      $this->requestInfo .= $this->body;
    }
    /*
     * 注意:这里的fsockopen中的url参数形式为"www.xxx.com"
     * 不能够带"http://"这种
     */
    $port = isset($this->urlinfo[&#39;port&#39;]) ? isset($this->urlinfo[&#39;port&#39;]) : &#39;80&#39;;
    $this->fp = fsockopen($this->urlinfo[&#39;host&#39;], $port, $errno, $errstr);
    if ( !$this->fp ) {
      echo $errstr.&#39;(&#39;.$errno.&#39;)&#39;;
      return false;
    }
    if ( fwrite($this->fp, $this->requestInfo) ) {
      $str = "";
      while ( !feof($this->fp) ) {
        $str .= fread($this->fp, 1024);
      }
      $this->responseInfo = $str;
    }
    fclose($this->fp);
    return $this->responseInfo;
  }
   
  private function parseurl($url) {
    $this->urlinfo = parse_url($url);
  }
}
// $url = "http://news.***.com/14/1102/01/AA0PFA7Q00014AED.html";
$url = "http://localhost/httppro/post.php";
$http = Http::create()->init($url);
/* 发送get请求 
echo $http->get(array(
  &#39;User-Agent&#39; => &#39;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36&#39;,
));
*/
 
/* 发送post请求 */
echo $http->post(array(
    &#39;User-Agent&#39; => &#39;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36&#39;,
), array(&#39;username&#39;=>&#39;发一个中文&#39;, &#39;age&#39;=>22));
로그인 후 복사

관련 권장 사항:

PHP의 파일 권한 기능 chmod에 대한 자세한 설명

PHP가 다음을 구현하는 방법에 대한 자세한 설명 후크 메커니즘

세부 사항 PHP 사용 이해 두 문자열 중 가장 긴 공통 부분 문자열 찾기

위 내용은 PHP가 소켓을 사용하여 HTTP 요청을 보내는 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿