<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Работа для  программистов &#187; неблокирующие сокеты</title>
	<atom:link href="http://job-interview.ru/articles/post/tag/%d0%bd%d0%b5%d0%b1%d0%bb%d0%be%d0%ba%d0%b8%d1%80%d1%83%d1%8e%d1%89%d0%b8%d0%b5-%d1%81%d0%be%d0%ba%d0%b5%d1%82%d1%8b/feed" rel="self" type="application/rss+xml" />
	<link>http://job-interview.ru/articles</link>
	<description>вакансии, вопросы, статьи</description>
	<lastBuildDate>Thu, 29 Mar 2012 20:53:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>“Многопоточность” в PHP (socket)</title>
		<link>http://job-interview.ru/articles/post/194</link>
		<comments>http://job-interview.ru/articles/post/194#comments</comments>
		<pubDate>Sun, 27 Dec 2009 13:21:34 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[асинхронные сокеты]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[неблокирующие сокеты]]></category>

		<guid isPermaLink="false">/articles/?p=194</guid>
		<description><![CDATA[Использование асинхронных сокетов.
Предлагаю вашему вниманию третью статью из цикла &#8220;Многопоточность&#8221; в  PHP. В данной статье мы рассмотрим асинхронные или неблокирующие сокеты.
Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование асинхронных сокетов.</h3>
<p>Предлагаю вашему вниманию третью статью из цикла <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в  PHP</a>. В данной статье мы рассмотрим <strong>асинхронные</strong> или <strong>неблокирующие сокеты</strong>.</p>
<p>Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у нас много и с ними производятся одинаковые действия. Хорошо, если бы можно было не дожидаться завершения соединения, а сразу же открывать следущее. И такая возможность существует.</p>
<p>Но сначала давайте разберем само <strong>понятие &#8220;сокет&#8221;</strong>. Что такое сокет?<br />
<span id="more-194"></span></p>
<blockquote><p><strong>Сокеты</strong>  — это название программного интерфейса для обеспечения информационного обмена между <em>процессами</em>. Процессы при таком обмене могут исполняться как на одном компьютере, так и на различных, связанных между собой сетью. <strong>Сокет</strong> — абстрактный объект, представляющий конечную точку соединения.</p></blockquote>
<p>В нашем случае сокет будет представлять собой соединение между нашей программой и компьютером, с которого требуется получить необходимую информацию.</p>
<p><em>Работа с сокетами</em> достаточно проста:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// создаем сокет</span>
<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// открываем сокет</span>
<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'80'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// записываем данные в сокет</span>
<span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #339933;">,</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// читаем данные из сокета</span>
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Сначала <em>функцией socket_create</em> инициализируем сокет и задаем его характеристики – флаг AF_INET, переданный в качестве первого параметра, указывает, что создается  сокет для интернета, второй параметр – тип сокета (самые распространенные – TCP и UDP)  нам нужен TCP-сокет &#8211; SOCK_STREAM, и третий параметр задает протокол (TCP).<br />
Затем с помощью <em>функции socket_connect</em> происходит соединение к указанному адресу и порту. Надо заметить, что эта функция принимает в качестве параметра не сам адрес хоста, а его ip адрес, поэтому сначала мы должны его определить <em>функцией gethostbyname</em>.<br />
Теперь нам надо <strong>сформировать запрос</strong>, который мы отправим на сервер (подробнее о <strong>http-заголовках</strong> можно почитать в <a href="/articles/post/86" target="_blank">статье PHP и HTTP</a>). Собственно отправку производит <em>функция socket_write</em>, второй параметр которой – это то, что мы отправляем и третий – длина отправляемой строки (т.е. всех сформированных заголовков).<br />
Запись произведена, теперь <em>функцией socket_read</em> читаем данные, переданные для нас сервером.<br />
В результате в переменной $result хранится хтмл, который нам необходим.</p>
<p>Задача у нас стоит та же, что и в предыдущих примерах: <em>получить содержимое нескольких html-страниц</em>. Вот код, реализующий это:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
	<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// таймаут для чтения</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_RCVTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут для записи</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_SNDTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// задаем неблокирующий режим сокетов</span>
	<span style="color: #990000;">socket_set_nonblock</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
	<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// соединяемся</span>
	<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">80</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
	<span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// продолжаем, пока есть задачи для записи или чтения</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
	<span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
	<span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
	<span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
			<span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
			<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #666666; font-style: italic;">// записываем в сокет</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
			<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// закрываем сокет</span>
			<span style="color: #990000;">socket_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// заносим html в массив результатов</span>
			<span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Можно заметить, что код несильно отличается от <a href="/articles/post/92#stream_code" target="_blank">кода для stream-функций</a>.</p>
<p>В общих словах здесь происходит следующее. Каждый сокет <em>инициализируется</em> и переводится в <em>неблокирующий режим</em>. Затем в цикле производится проверка готовых к чтению или записи сокетов, и если такие существуют, производится соответствующая операция. Все действия протекают в <em>асинхронном порядке</em>, т.е не ждут окончания предыдущей операции. Например, если данные с мэйл.ру поступили раньше, чем от яндекса, то будут обрабатываться именно они, хотя коннект к яндексу мог произойти до коннекта к мэйлу. Можно сказать, что все происходит в несколько &#8220;потоков&#8221;, когда параллельно ожидается готовность каждого сокета к какому-либо действию.</p>
<p>Теперь разберем код более подробно.<br />
Итак, у нас есть массив с адресами страниц. В строке 9 запускается цикл для инициализации соединения с каждым хостом. В 11 строке создается сокет, затем в 15 и 17 строках мы задаем таймауты для чтения и записи соответственно. В 19 строчке <em>функцией socket_set_nonblock</em> задаем <strong>неблокирующий режим,</strong> превращающий каждый наш сокет в <strong>асинхронный</strong>. Это необходимо для того, чтобы после очередной операции над сокетом не происходило ожидание ее окончания, а продолжал работу остальной код программы. В 26 строке заносим инициализированный сокет в массив сокетов для записи.</p>
<p>Основной цикл начинается в 30 строчке. Он будет продолжаться до тех пор, пока у нас остаются сокеты, в которые нужно записать или из которых надо прочитать.<br />
В 32 строке массиву $rtasks_ присваиваем массив сокетов, из которых должна быть прочитана информация. В 34-ой в $wtasks_ заносится массив с сокетами, в которые необходимо произвести запись.<br />
Главная функция в этом цикле &#8211; <em>socket_select</em>. Она принимает на вход массивы сокетов, ожидающих чтения, ожидающих запись и массив для исключительных ситуаций, четвертый параметр, передаваемый в данную функцию – таймаут. Параметры-массивы передаются по ссылке, т.е когда произойдет ожидаемое событие (<em>socket_select</em> в этом случае вернет число больше 0), в них появятся соответствующие дескрипторы.<br />
Если нашлись сокеты, доступные для записи, ищем урл, соответствующий каждому из готовых сокетов, и <em>функцией socket_write</em> записываем в него заголовки для получения хтмл страницы в ответе. Так же в 44-ой строке удаляем дескриптор из массива для записи, так как она будет произведена, и заносим его в строке 46 в массив для чтения, чтобы потом получить интересующий нас ответ.<br />
Если же имеются сокеты, готовые нам ответить, считываем из них информацию <em>функцией socket_read</em>.<br />
Profit! В массиве $results содержится вожделенный хтмл-код!</p>
<p><b>Замечание:</b><br />
<i>При вызове функции socket_connect, когда сокет переведен в неблокирующий режим функцией socket_set_nonblock, выдается предупреждение <b style="color: red;">&#8220;Operation now in progress&#8221; (&#8221;Операция на незаблокированном сокете не может быть завершена немедленно&#8221;)</b>, а socket_connect возвращает false. Несмотря на это, код нормально отрабатывает.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/194/feed</wfw:commentRss>
		<slash:comments>12549</slash:comments>
		</item>
	</channel>
</rss>
