PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Sockets/Sockets.tex

https://github.com/KWMalik/PharoByExample-english
LaTeX | 695 lines | 557 code | 102 blank | 36 comment | 0 complexity | 7b26edb62adc25caf86c3d0aea41b82a MD5 | raw file
  1. % $Author$
  2. % $Date$
  3. % $Revision$
  4. % 2011-09-11 - Migrated to PharoBox: svn checkout https://XXX@scm.gforge.inria.fr/svn/pharobooks/PharoByExampleTwo-Eng
  5. % could change returns by answers
  6. %=================================================================
  7. \ifx\wholebook\relax\else
  8. % --------------------------------------------
  9. % Lulu:
  10. \documentclass[a4paper,10pt,twoside]{book}
  11. \usepackage[
  12. papersize={6in,9in},
  13. hmargin={.75in,.75in},
  14. vmargin={.75in,1in},
  15. ignoreheadfoot
  16. ]{geometry}
  17. \input{../common.tex}
  18. \pagestyle{headings}
  19. \setboolean{lulu}{true}
  20. % --------------------------------------------
  21. % A4:
  22. % \documentclass[a4paper,11pt,twoside]{book}
  23. % \input{../common.tex}
  24. % \usepackage{a4wide}
  25. % --------------------------------------------
  26. \graphicspath{{figures/} {../figures/}}
  27. \begin{document}
  28. %\renewcommand{\nnbb}[2]{} % Disable editorial comments
  29. \sloppy
  30. \fi
  31. %=================================================================
  32. %Noury's commands
  33. \newcommand{\nouryComment}[1]{}
  34. %\newcommand{\nouryComment}[1]{\textcolor{red}{\textbf{\emph{#1}}}}
  35. %=================================================================
  36. \chapter{Sockets}\label{cha:sockets}
  37. \chapterauthor{\authornoury{}}
  38. Modern applications are often distributed on multiple devices and collaborate through a network to achieve some task.
  39. The basic approach to set up such a collaboration is to use \textit{sockets}.
  40. A typical use is in the World Wide Web. Browsers and servers interact through HTTP sockets.
  41. The concept of socket was first introduced by researchers from Berkeley University in the 1960s. They defined the first socket API for the C programming language in the context of Unix operating systems. Since then, the concept of socket was spread out to other operating systems.
  42. Its API was ported to most existing programming languages including Smalltalk.
  43. In this chapter, we present the API of sockets in the context of Pharo.
  44. We first show through some examples how to use sockets for building both clients and servers.
  45. Then, we introduce \ct!SocketStream! and how to use it.
  46. In practice, one is likely to use \ct!SocketStream! instead of plain sockets.
  47. \section{Basic Concepts}
  48. \subsection{Socket}
  49. A remote communication involves at least two system processes exchanging some data bytes through a network. Each process accesses the network through at least one socket (see Figure~\ref{fig:socketConcept}).
  50. A socket can then be defined as a \textit{plug on a communication network}.
  51. \begin{figure}[ht]\centering
  52. \includegraphics[width=.75\linewidth]{socketConcept}
  53. \caption{Inter-Process Remote Communication Through Sockets.}
  54. \label{fig:socketConcept}
  55. \end{figure}
  56. Sockets are used to achieve a bidirectional communication. They allow both sending and receiving data.
  57. Such interaction can be done according to communication protocols which are encapsulated by sockets. On the Internet and other networks such as ethernet LANs\footnote{Local Area Networks.}, two basic protocols widely used are \textit{TCP/IP} and \textit{UDP/IP}.
  58. \subsection{TCP/IP vs. UDP/IP}
  59. TCP/IP stands for \textit{Transmission Control Protocol / Internet Protocol} (TCP for short).
  60. TCP use guarantees a reliable communication (no data loss). It requires that applications involved in the communication get connected before actually communicating.
  61. Once a connection is established interacting parties can send and receive an arbitrary amount of bytes. This is often referred to as a \textit{stream communication}.
  62. Data reach the destination in the same order of their sending.
  63. UDP/IP stands for \textit{User Datagram Protocol / Internet Protocol} (UDP for short).
  64. Datagrams are chunks of data which size cannot exceed 64KB.
  65. UDP is an unreliable protocol because of two reasons.
  66. First, UDP does not guarantee that datagrams will actually reach there destination.
  67. The second reason why UDP is qualified as unreliable is that the reception order of multiple datagrams from a single sender to some particular receiver may arrive in an arbitrary order.
  68. Nevertheless, UDP is faster than TCP since no connection is required before sending data.
  69. A typical use of UDP is ``heart-beating'' as used in server-based social application, where clients need to notify the server their status (\eg Requesting interactions, or Invisible).
  70. \nouryComment{In a future version we will present UDP. But, so far UDP does not work in \pharo.}
  71. In the remainder of this chapter we will focus on TCP Sockets.
  72. First, we show how to create a client socket, connect it to a server, exchange data and close the connection (section~\ref{sec:clientTcpSocket}).
  73. This lifecycle is illustrated using examples showing the use of client sockets to interact with a web server.
  74. Next, section~\ref{sec:serverTcpSocket} presents server sockets.
  75. We describe their life-cycle and how to use them to implement a server that can handle multiple concurrent connections.
  76. Last, we introduce in section~\ref{sec:socketStream} socket streams.
  77. We give an overview of their benefits by describing their use on both client and server side.
  78. \section{TCP Client}
  79. \label{sec:clientTcpSocket}
  80. We call \textit{TCP client} an application that initiates a TCP connection to exchange data with another application: the \textit{server}.
  81. It is important to mention that the client and the server may be developed in different languages.
  82. The life-cycle of such a client in \pharo decomposes into 4 steps:
  83. \begin{enumerate}
  84. \item Create a TCP socket.
  85. \item Connect the socket to some server.
  86. \item Exchange data with the server through the socket.
  87. \item Close the socket.
  88. \end{enumerate}
  89. \subsection{Create a TCP Socket}
  90. \pharo provides a single socket class.
  91. At creation, the socket type (TCP or UDP) is provided to the socket plugin of the virtual machine.
  92. To create a TCP socket, you need to evaluate the following message
  93. \begin{code}{}
  94. Socket newTCP
  95. \end{code}
  96. Method \ct!newTCP! hands out the tcp type (which is stored in the class variable \ct!TCPSocketType!) to set up a TCP socket.
  97. \subsection{Connect a TCP Socket to some Server}
  98. To connect a TCP Socket to a server, you need to have the object representing the IP address of that server. This address is an instance of \ct!SocketAddress!.
  99. A handy way to create it is to use \ct!NetNameResolver! that provides IP style network name lookup and translation facilities.
  100. \Scrref{creatingSocketAddress} provides two examples of socket address creation.
  101. The first one creates an address from a string describing the server name (\ct!'www.esug.org'!), while the second does the creation from a string representing the IP address of the server (\ct!'127.0.0.1'!).
  102. Note that to use the \ct!NetNameResolver! you need to have your machine connected to a network with a DNS\footnote{\emph{Domain Name System}: basically a directory that maps device names to their IP address.}.
  103. The only exception is for retrieving the local host address, i.e. \ct!127.0.0.1! which is the generic address to refer to the machine that runs your software (\pharo here).
  104. \nouryComment{There are dedicated methods for retrieving the localhost address but they are buggy at the time of writing this text.}
  105. \nouryComment{The NameLookupFailure exception is used ONLY in NetNameResolver class>>addressForName:timeout:. It should be more widely used.}
  106. \begin{script}[creatingSocketAddress]{Creating a Socket Address}
  107. | esugAddress localAddress |
  108. esugAddress := NetNameResolver addressForName: 'www.esug.org'.
  109. localAddress := NetNameResolver addressForName: '127.0.0.1'.
  110. \end{script}
  111. Now we can connect our TCP socket to the server as shown in \Scrref{connectingTcpSocket}.
  112. Message \ct!connectTo:port:! attempts to connect the socket to the server which address and port are provided as parameters.
  113. \nouryComment{SocketAddress can also store the port of the server.
  114. But, NetNameResolver does NOT support building socket address WITH port.}
  115. \begin{script}[connectingTcpSocket]{Connecting a TCP Socket to ESUG Server.}
  116. | clientSocket serverAddress |
  117. clientSocket := Socket newTCP.
  118. serverAddress := NetNameResolver addressForName: 'www.esug.org'.
  119. clientSocket
  120. connectTo: serverAddress port: 80;
  121. waitForConnectionFor: 10.
  122. clientSocket isConnected
  123. \end{script}
  124. The \ct!connectTo:port:! message returns immediately after issuing to the system (through a primitive call) the request to connect the socket.
  125. Message \ct!waitForConnectionFor: 10! suspends the current process until the socket is connected to the server.
  126. It waits at most \ct!10! seconds as requested by the parameter.
  127. If the socket is not connected after 10 seconds, the \ct!ConnectionTimedOut! exception is signaled.
  128. Otherwise, the execution can proceed by evaluating the expression \ct!clientSocket isConnected! which obviously answers \ct!true!.
  129. \subsection{Exchange Data with Server}
  130. \label{sec:exchangeData}
  131. Once connection is established, the client can send/receive data to/from the server.
  132. By data we mean a \ct!ByteString!\footnote{One can send a \ct!ByteArray!, but the receiving socket will return a \ct!ByteString! however.}.
  133. Typically, the client sends some request to the server and then expects receiving some response.
  134. Web browsers act according to this schema.
  135. A web browser is a client that issues a request to some web server identified by the URL.
  136. Such request is often the path to some resource on the server such as a html file or a picture.
  137. Then, the browser awaits the server response (\eg html code, picture bytes).
  138. \begin{script}[dataExhangeWithTcpSocket]{Exchanging Data with some Server through a TCP Socket.}
  139. |clientSocket data|
  140. ... ``create and connect the TCP clientSocket''
  141. clientSocket sendData: 'Hello server'.
  142. data := clientSocket receiveData.
  143. ... ``Process data''
  144. \end{script}
  145. \Scrref{dataExhangeWithTcpSocket} shows the protocol to send and receive data through a client socket.
  146. Here, we send the string \ct-'Hello server!'- to the server using the \ct!sendData:! message.
  147. Next, we send the \ct!receiveData! to our client socket to make it wait for data reception.
  148. Then, the contents of variable \ct!data! is processed.
  149. \begin{script}[dataReceptionTimeOut]{Bounding the Maximum Time for Data Reception.}
  150. |clientSocket data|
  151. ... ``create and connect the TCP clientSocket''
  152. [data := clientSocket receiveDataTimeout: 5.
  153. ... ``Process data''
  154. ] on: ConnectionTimedOut
  155. do: [:timeOutException|
  156. Transcript
  157. cr;
  158. show: 'No data receivedBANG';
  159. space;
  160. show: 'Network connection is too slow or server is down.']
  161. \end{script}
  162. %Timeout
  163. Note that by using \ct!receiveData!, the client waits until the server either sends no more data, or closes the connection.
  164. This means that the client may wait indefinitely.
  165. An alternative is to have the client signal a \ct!ConnectionTimedOut! exception if it had waited too much as shown in \scrref{dataReceptionTimeOut}.
  166. We use message \ct!receiveDataTimeout:! to ask the client socket to wait for 5 seconds.
  167. If data is received during this period of time, it is processed silently.
  168. But if no data is received during the 5 seconds, a \ct!ConnectionTimedOut! is signaled.
  169. So, we log a description of what happened on the \ct!Transcript!.
  170. \subsection{Close a Socket}
  171. A TCP socket remains alive while devices at both ends are connected.
  172. Once the interaction is over, either the server or the client can decide to close the socket.
  173. This can be done by sending the \ct!close! message to the socket.
  174. The image where this message is evaluated will then send a close request to the other side.
  175. The socket remains connected until the other side closes it.
  176. This may last indefinitely when there is a network failure or when the other side is down.
  177. This is why sockets also answer the \ct!destroy! message, which frees system resources required by the socket.
  178. In practice we use \ct!closeAndDestroy!. It first attempts to close the socket by sending the \ct!close! message.
  179. Then, if the socket is still connected after a duration of 20 seconds, the socket is destroyed.
  180. Note that there exist a variant \ct!closeAndDestroy: seconds! which gets as a parameter the duration to wait before destroying the socket.
  181. \begin{script}[script:closeAndDestroy]{Closing a TCP Socket After Connection to a Web Site.}
  182. | clientSocket serverAddress httpQuery htmlText |
  183. httpQuery := 'GET / HTTP/1.1', String crlf,
  184. 'Host: www.esug.org:80', String crlf,
  185. 'Accept: text/html', String crlfcrlf.
  186. Transcript cr; cr; show: 'Attempt to get a web page...'.
  187. serverAddress := NetNameResolver addressForName: 'www.esug.org'.
  188. clientSocket := Socket newTCP.
  189. [clientSocket
  190. connectTo: serverAddress port: 80;
  191. waitForConnectionFor: 10.
  192. clientSocket sendData: httpQuery.
  193. htmlText := clientSocket receiveDataTimeout: 5.
  194. Transcript cr; show: htmlText.
  195. ] ensure: [clientSocket closeAndDestroy].
  196. Transcript cr; show: '...Done'
  197. \end{script}
  198. To summarize all steps described so far, we use the example of getting a web page from a server in \Scrref{script:closeAndDestroy}.
  199. First, we retrieve the IP address of the \url{www.esug.org} server.
  200. Then, we create a TCP socket and connect it to the server.
  201. We use the IP address we get in the previous step and the default port for web servers: 80.
  202. Next we forge the HTTP\footnote{HyperText Transfer Protocol used for web communications.} query.
  203. The string corresponding to our query starts with the \ct!GET! keyword, followed by a slash saying that we are requesting the root file of the server.
  204. Follows the protocol version \ct!HTTP/1.1!.
  205. The second line recalls the host name and port.
  206. The third and last line of the HTTP query refers to format accepted by our client.
  207. Since, we intend to display the result of our query on the \ct!Transcript!, we state that our client accepts texts with html format.
  208. After sending the http query, we wait at most 5 seconds for the html text that we display on the \ct!Transcript!.
  209. Socket connection, query sending and html reception are inside a block which execution is ensured to end with cleaning up socket related resources, by means of the \ct!closeAndDestroy! message.
  210. \section{TCP Server}
  211. \label{sec:serverTcpSocket}
  212. Now, let us build a simple TCP server. A \textit{TCP Server} is an application that awaits TCP connections from TCP clients. Once connection established, both the server and the client can send a receive data in any order.
  213. A big difference between the server and the client is that the server uses at least two sockets.
  214. One socket is used for handling client connections, while the second serves for exchanging data with a particular client.
  215. \subsection{TCP Socket Server Life-cycle}
  216. The life-cycle of a TCP server in \pharo has 5 steps:
  217. \begin{enumerate}
  218. \item Create a first TCP socket labelled \textit{socket$_1$}.
  219. \item Wait for connections by making \textit{socket$_1$} listen on some port.
  220. \item Accept a client request for connection. As a result, \textit{socket$_1$} will build a second socket labelled \textit{socket$_2$}.
  221. \item Exchange data with the client through \textit{socket$_2$}. In the meanwhile, \textit{socket$_1$} can continue to wait for connections, and possibly create new sockets to exchange data with other clients.
  222. \item Close \textit{socket$_2$}.
  223. \item Close \textit{socket$_1$} when we decide to kill the server and stop accepting client connections.
  224. \end{enumerate}
  225. Concurrency is implicit in this life-cycle.
  226. The server listens for incoming client connection requests through \textit{socket$_1$}, while exchanging data with some clients through \textit{socket$_2$}.
  227. The server can even simultaneously exchange data with multiple clients through different sockets.
  228. In the following, we first illustrate the socket serving machinery.
  229. Then, we give a complete server class and explain the server life-cycle and related concurrency issues.
  230. \subsection{Serving Basic Example}
  231. We illustrate the serving basics through a simple example of an echo TCP server that accepts a single client request.
  232. It sends back to clients whatever data it received and quits.
  233. The code is provided by \Scrref{servingBasicExample}.
  234. \begin{script}[servingBasicExample]{Basic Echo Server.}
  235. | connectionSocket interactionSocket |
  236. connectionSocket := Socket newTCP.
  237. connectionSocket listenOn: 9999 backlogSize: 10.
  238. interactionSocket := connectionSocket waitForAcceptFor: 60.
  239. connectionSocket closeAndDestroy.
  240. receivedData := interactionSocket receiveData.
  241. Transcript cr; show: receivedData.
  242. interactionSocket sendData: 'ECHO: ', receivedData.
  243. interactionSocket closeAndDestroy.
  244. \end{script}
  245. First, we create the socket that we will use for handling incoming connections.
  246. We configure it to listen on port 9999.
  247. The \ct!backlogSize! is set to 10, meaning that we ask the Operating System to allocate a buffer for 10 connection requests.
  248. This backlog will not be actually used in this example.
  249. But, a more realistic server will have to handle multiple connections and then store pending connection requests into the backlog.
  250. Once the connection socket (referenced by variable \ct!connectionSocket!) is set up, it starts listening for client connections.
  251. The \ct!waitForAcceptFor: 60! message makes the socket wait connection requests for 60 seconds.
  252. If no client attempts to connect during these 60 seconds, the message answers \ct!nil!.
  253. Otherwise, we get a new socket \ct!interactionSocket! connected the client's socket.
  254. At this point, we do not need the connection socket anymore, so we can close it (\ct!connectionSocket closeAndDestroy! message).
  255. Since the interaction socket is already connected to the client, we can use it to exchange data.
  256. Messages \ct!receiveData! and \ct!sendData:! presented above (see section~\ref{sec:exchangeData}) can be used to achieve this goal.
  257. In our example, we wait for data from the client, next we display it on the \ct!Transcript!, and last we send it back to the client prefixed with the \ct!'ECHO: '! string.
  258. Last, we finish the interaction with the client by closing the interaction socket.
  259. \begin{script}[echoClient]{Echo Client.}
  260. | clientSocket serverAddress echoString |
  261. serverAddress := NetNameResolver addressForName:'127.0.0.1'.
  262. clientSocket := Socket newTCP.
  263. [clientSocket
  264. connectTo: serverAddress port: 9999;
  265. waitForConnectionFor: 10.
  266. clientSocket sendData: 'Hello PharoBANG'.
  267. echoString := clientSocket receiveDataTimeout: 5.
  268. Transcript cr; show: echoString.
  269. ] ensure: [clientSocket closeAndDestroy].
  270. \end{script}
  271. You cannot test this script totally without having the client code running, for example in a different process or a second image.
  272. We do use two different images, one that runs the server code and one for the client code.
  273. Indeed, since we use the user interaction process, the \pharo UI will be frozen at some points, such as during the \ct!waitForAcceptFor:!.
  274. \Scrref{echoClient} provides the code to run on the client image.
  275. Note that you have to run the server code first.
  276. Otherwise, the client will fail.
  277. %An alternative to running your own Smalltalk client socket is to use an existing one.
  278. %On Unix machines, the \ct{nc}\footnote{\ct{nc} stands for \ct{netcat}.} utility is very handy for experimenting with sockets.
  279. %It can play either a client or a server role for both TCP and UDP.
  280. %To run an \ct{nc}-based client for our server, evaluate the following expression on terminal:
  281. %\begin{code}{}
  282. %cat | nc localhost 9999
  283. %\end{code}
  284. %
  285. %The \ct{cat} command allows you to type-in some text.
  286. %Once you're done, type \ct{ctrl-D}.
  287. %The pipe connects the output of \ct{cat} to the input of \ct{nc}.
  288. %Here, we use \ct{nc} as client that sends the text we provided to a server on the local host, listening on port 9999.
  289. \subsection{Echo Server Class}\label{sec:echoServerClass}
  290. We define here the \ct!EchoServer! class that deals with concurrency issues.
  291. It handles concurrent client queries and it does not freeze the UI.
  292. As we can see in the definition labelled \clsref{echoServerClassDef}, the \ct!EchoServer! declares three instance variables.
  293. The first one (\ct!connectionSocket!) refers to the socket used for listening to client connections.
  294. The two last instance variables (\ct!isRunning! and \ct!isRunningLock!) are used to manage the server process life-cycle while dealing with synchronization issues.
  295. \begin{classdef}[echoServerClassDef]{\ct!EchoServer! Class Definition}
  296. Object subclass: #EchoServer
  297. instanceVariableNames: 'connectionSocket isRunning isRunningLock'
  298. classVariableNames: ''
  299. poolDictionaries: ''
  300. category: 'SimpleSocketServer'
  301. \end{classdef}
  302. \begin{method}[meth:serverInitialize]{The \ct!EchoServer>>>initialize! Method}
  303. EchoServer>>>initialize
  304. super initialize.
  305. isRunningLock := Mutex new.
  306. self isRunning: false
  307. \end{method}
  308. \begin{method}[meth:isRunningRead]{The \ct!EchoServer>>>isRunning! Read Accessor}
  309. EchoServer>>>isRunning
  310. ^isRunningLock critical: [isRunning]
  311. \end{method}
  312. \begin{method}[meth:isRunningWrite]{The \ct!EchoServer>>>isRunning:! Write Accessor}
  313. EchoServer>>>isRunning: aBoolean
  314. isRunningLock critical: [isRunning := aBoolean]
  315. \end{method}
  316. The \ct! isRunning! instance variable is a flag that is set to \ct!true! while the serving is running.
  317. As we will see below, it can be accessed by different processes.
  318. Therefore, we use the mutex (see \mthref{meth:serverInitialize}) referenced using the \ct!isRunningLock! instance variable.
  319. This mutex ensures that a single process can read or write the value of \ct!isRunning! (use of the \ct!critical:! message in \mthref{meth:isRunningRead} and \mthref{meth:isRunningWrite}).
  320. \begin{method}[meth:stop]{The \ct!EchoServer>>>stop! Method}
  321. EchoServer>>>stop
  322. self isRunning: false
  323. \end{method}
  324. In order to manage the life-cycle of our server, we introduced two methods \ct!EchoServer>>>start! and \ct!EchoServer>>>stop!.
  325. We begin with the simplest one \ct!EchoServer>>>stop! which definition is provided as \mthref{meth:stop}.
  326. It simply sets the \ct!isRunning! flag to \ct!false!.
  327. This will have the consequence of stopping the serving loop in method \ct!EchoServer>>>serve! (see \mthref{meth:serve}).
  328. \begin{method}[meth:serve]{The \ct!EchoServer>>>serve! Method}
  329. serve
  330. | interactionSocket |
  331. [[self isRunning]
  332. whileTrue: [self interactOnConnection]]
  333. ensure: [connectionSocket closeAndDestroy]
  334. \end{method}
  335. The activity of the serving process is implemented in the \ct!serve! method (see \mthref{meth:serve}).
  336. It interacts with clients on connections while the \ct!isRunning! flag is \ct!true!.
  337. After a \ct!stop!, the serving process is terminates by destroying the connection socket.
  338. The \ct!ensure:! message guarantees that that this destruction is performed even if the serving process is terminated abnormally.
  339. Such termination may occur because of an exception (\eg network disconnection) or a user action (\eg through the process browser).
  340. \begin{method}[meth:start]{The \ct!EchoServer>>>start! Method}
  341. start
  342. isRunningLock critical: [
  343. self isRunning ifTrue: [^self].
  344. self isRunning: true].
  345. connectionSocket := Socket newTCP.
  346. connectionSocket listenOn: 9999 backlogSize: 10.
  347. [self serve] fork
  348. \end{method}
  349. The creation of the serving process is the responsibility of method \ct!EchoServer>>>start! (see the last line of \mthref{meth:start}).
  350. The \ct!EchoServer>>>start! method first checks if the server is already running.
  351. It returns if the \ct!isRunning! flag is set to \ct!true!.
  352. Otherwise, a TCP socket dedicated to connection handling is created and made to listen on port 9999.
  353. The backlog size is set to 10 that is -as mentioned above- the system allocates a buffer for storing 10 pending client connection requests.
  354. This value is a trade-off that depends on how fast is the server (varies according to the VM and the hardware) and the maximum rate of client connections requests.
  355. The backlog size should be big enough to avoid losing any connection request, but not too big to avoid wasting memory.
  356. Finally \ct!EchoServer>>>start! method creates a process by sending the \ct!fork! message to the \ct![self serve]! block.
  357. The created process has the same priority as the creator process (i.e. the one that performs the \ct!EchoServer>>>start! method).
  358. \begin{method}[meth:interactOnConnection]{The \ct!EchoServer>>>interactOnConnection! Method}
  359. interactOnConnection
  360. | interactionSocket |
  361. interactionSocket := connectionSocket waitForAcceptFor: 1 ifTimedOut: [^self].
  362. [self interactUsing: interactionSocket] fork
  363. \end{method}
  364. Method \ct!EchoServer>>>serve! (see \mthref{meth:serve}) loop interacts with clients on connections.
  365. This interaction is handled in the \ct!EchoServer>>>interactOnConnection! method (see \mthref{meth:interactOnConnection}) .
  366. First, the connection socket waits for client connections for one second.
  367. If no client attempts to connect during this period we simply return.
  368. Otherwise, we get as result another socket dedicated to interaction.
  369. To process other client connection requests, the interaction is performed in another process, hence the \ct!fork! in the last line.
  370. \begin{method}[meth:interactUsing]{The \ct!EchoServer>>>interactUsing:! Method}
  371. interactUsing: interactionSocket
  372. | receivedData |
  373. [receivedData := interactionSocket receiveDataTimeout: 5.
  374. Transcript cr; show: receivedData.
  375. interactionSocket sendData: 'ECHO: ', receivedData]
  376. ensure: [interactionSocket closeAndDestroy]
  377. \end{method}
  378. The interaction as implemented in method \ct!EchoServer>>>interactUsing:! (see \mthref{meth:interactUsing}) with a client boils down to reading data provided by the client and sending it back prefixed with the \ct!'ECHO: '! string.
  379. It worth noting that we ensure that the interaction socket is destroyed, whether we have exchanged data or not (timeout).
  380. \section{SocketStream}
  381. \label{sec:socketStream}
  382. \ct!SocketStream! is a read-write stream that encapsulates a TCP socket.
  383. It eases the data exchange by providing buffering together with a set of facility methods.
  384. \subsection{SocketStream at Client Side}
  385. We illustrate here socket stream use at client side.
  386. The following code snippet (\Scrref{script:streamGetLine}) shows how the client uses a socket stream to get the first line of a webpage.
  387. \begin{script}[script:streamGetLine]{Getting the first line of a web page using \ct!SocketStream!.}
  388. |stream httpQuery result|
  389. stream := SocketStream
  390. openConnectionToHostNamed: 'www.pharo-project.org'
  391. port: 80.
  392. httpQuery := 'GET / HTTP/1.1', String crlf,
  393. 'Host: www.pharo-project.org:80', String crlf,
  394. 'Accept: text/html', String crlf.
  395. [
  396. stream sendCommand: httpQuery.
  397. Transcript cr; show: stream nextLine.
  398. ] ensure: [
  399. stream close]
  400. \end{script}
  401. The first line creates a stream that encapsulates a newly created socket connected to the provided server.
  402. It is the responsibility of message \ct!openConnectionToHostNamed:port:!.
  403. It suspends the execution until the connection with the server is established.
  404. If the server does not respond, the socket stream signals a \ct!ConnectionTimedOut! exception.
  405. This exception is actually signaled by the underlying socket.
  406. The default timeout delay is 45 seconds (defined in method \ct!Socket class>>>standardTimeout!).
  407. One can choose a different value using the \ct!SocketStream>>>timeout:! method.
  408. Once our socket stream connected to the server, we forge and send an HTTP GET query.
  409. Notice that compared to \scrref{script:closeAndDestroy} we skipped here (\Scrref{script:streamGetLine}) one final \ct!String crlf!.
  410. This is because the \ct!SocketStream>>>sendCommand:! method automatically inserts CR and LF characters after sent data to mark line ending.
  411. Reception of the requested web page is triggered by sending the \ct!nextLine! message to our socket stream.
  412. It will waits a few seconds until data is received.
  413. Data is then displayed on the transcript.
  414. We safely ensure that the connection is closed.
  415. In this example, we only display the first line of response sent by the server.
  416. We can easily display the full response including the html code by sending the \ct!upToEnd! message to our socket stream.
  417. Note however that you will have to wait a bit longer compared to displaying a single line.
  418. \subsection{SocketStream at Server Side}
  419. SocketStreams may also be used at server side to wrap the interaction socket as shown in \Scrref{script:streamSimpleServer}.
  420. \begin{script}[script:streamSimpleServer]{Simple Server using \ct!SocketStream!.}
  421. |connectionSocket interactionSocket interactionStream|
  422. connectionSocket := Socket newTCP.
  423. [
  424. connectionSocket listenOn: 12345 backlogSize: 10.
  425. interactionSocket := connectionSocket waitForAcceptFor: 30.
  426. interactionStream := SocketStream on: interactionSocket.
  427. interactionStream sendCommand: 'Greetings from Pharo Server'.
  428. Transcript cr; show: interactionStream nextLine.
  429. ] ensure: [
  430. connectionSocket closeAndDestroy.
  431. interactionStream ifNotNil: [interactionStream close]
  432. ]
  433. \end{script}
  434. A server relying on socket streams still uses a socket for handling incoming connection requests.
  435. Socket streams come into action once a socket is created for interaction with a client.
  436. The socket is wrapped into a socket stream that eases data exchange using messages such as \ct!sendCommand:! or \ct!nextLine!.
  437. Once we are done, we close and destroy the socket handling connections and we close the interaction socket stream.
  438. This latter will take care of closing and destroying the underlying interaction socket.
  439. \subsection{Binary vs. Ascii mode}
  440. Data exchanged can be treated as bytes or characters depending.
  441. When a socket stream is configured to exchange bytes by means of message \ct!binary! it organizes sent and received data as byte arrays.
  442. Conversely, when a socket stream is configured to exchange characters (default setting) by means of message \ct!ascii! it organizes sent and received data as Strings.
  443. Suppose we have an instance of the \ct!EchoServer! (see section~\ref{sec:echoServerClass}) started by means of the following expression
  444. \begin{code}{}
  445. server := EchoServer new.
  446. server start.
  447. \end{code}
  448. The default behavior of socket stream is to handle ascii strings on sends and receptions.
  449. We show instead in \Scrref{script:binarySocketStream} the behavior in binary mode.
  450. The \ct!nextPutAllFlush:! message receives a byte array as argument.
  451. It puts all the bytes into the buffer then immediately triggers the sending (hence the \ct!Flush! in the selector).
  452. The \ct!upToEnd! message answers an array with all bytes sent back by the server.
  453. Note that this message blocks until the connection with the server is closed.
  454. \begin{script}[script:binarySocketStream]{A \ct!SocketStream! Interacting in Binary Mode.}
  455. interactionStream := SocketStream
  456. openConnectionToHostNamed: 'localhost' port: 9999.
  457. interactionStream binary.
  458. interactionStream nextPutAllFlush: #[65 66 67].
  459. interactionStream upToEnd.
  460. \end{script}
  461. It is worth noting that whether the client manages strings (ascii mode) or byte arrays (binary mode) has no impact on the server.
  462. Indeed, in ascii mode, the socket stream handles instances of \ct!ByteString!.
  463. So, each character maps to a single byte.
  464. \subsection{Delimiting Data}
  465. SocketStream acts simply as a gateway to some network.
  466. It sends or reads bytes without giving them any semantics.
  467. The semantics, that is the organization and meaning of exchanged data should be handled by other objects.
  468. Developers should decide a protocol to use and to enforce on both interacting sides in order to have correct interaction.
  469. A good practice is to \emph{reify} a protocol, that is to materialize it as an object which wraps a socket stream.
  470. The protocol object analyzes exchanged data and decides accordingly which messages to send to the socket stream.
  471. Involved entities in any conversation need a protocol that defines how to organize data into sequence of bytes or characters.
  472. Senders should conform to this organization to allow receivers extract valid data from received sequence of bytes.
  473. One possible solution is to have a set of delimiters inserted between bytes or characters corresponding to each data.
  474. An example of delimiter is the sequence of ASCII characters CR and LF.
  475. This sequence is considered so useful that the developers of the \ct!SocketStream! class introduced the \ct!sendCommand:! message.
  476. This method (illustrated in \scrref{script:closeAndDestroy}) does append CR and LF after sent data.
  477. When reading CR followed by LF the receiver knows that the received sequence of characters is complete and can be safely converted into valid data.
  478. A facility method \ct!nextLine! (illustrated in \scrref{script:streamGetLine}) is implemented by \ct!SocketStream! to perform reading until the reception of CR+LF sequence.
  479. One can however use any character or byte as a delimiter.
  480. Indeed, we can ask a socket stream to read all characters/bytes up to some specific one using the \ct!upTo:! message.
  481. The advantage of using delimiters is that it handles data of arbitrary size.
  482. The cons is that we need to analyze received bytes or characters to find out the limits, which is resource consuming.
  483. An alternative approach is to exchanged bytes or characters organized in chunks of a fixed size.
  484. A typical use of this approach is for streaming audio or video contents.
  485. \begin{script}[script:streamNextPutAllStartingAt]{A content streaming source sending data in chunks.}
  486. interactionStream := "create an instance of SocketStream".
  487. contentFile := FileStream fileNamed: '/Users/noury/Music/mySong.mp3'.
  488. contentFile binary.
  489. content := contentFile upToEnd.
  490. chunkSize := 3000.
  491. chunkStartIndex := 1.
  492. [chunkStartIndex < content size] whileTrue: [
  493. interactionStream next: chunkSize putAll: content startingAt: chunkStartIndex.
  494. chunkStartIndex := chunkStartIndex + chunkSize.
  495. ]
  496. interactionStream flush.
  497. \end{script}
  498. \Scrref{script:streamNextPutAllStartingAt} gives an example of a script streaming an mp3 file.
  499. First we open a binary (mp3) file and retrieve all its content (message \ct!upToEnd:!).
  500. Then we loop, sending data in chunks of 3000 bytes.
  501. We rely on the \ct!next:putAll:startingAt:! message that takes three arguments: the size (number of bytes or characters) of the data chunk,
  502. the data source (a sequenceable collection) and the index of the first element of the chunk.
  503. In this example, we make the assumption that the size of the content collection is a multiple of the chunk size.
  504. Of course, in a real setting, this assumption does not hold and one needs to deal with the last part of data that is smaller than a chunk.
  505. A possible solution is to replace missing bytes with zeros.
  506. \begin{script}[script:socketStreamNext]{Reading data in chunks using \ct!SocketStream!.}
  507. |interactionStream chunkSize chunk|
  508. interactionStream := SocketStream
  509. openConnectionToHostNamed: 'localhost' port: 9999.
  510. interactionStream isDataAvailable ifFalse: [(Delay forMilliseconds: 100) wait].
  511. chunkSize := 5.
  512. [interactionStream isDataAvailable] whileTrue: [
  513. chunk := interactionStream next: chunkSize.
  514. Transcript cr; show: chunk
  515. ].
  516. interactionStream close.
  517. Transcript cr; show: 'DONE!'
  518. \end{script}
  519. In order to read data in chunks, \ct!SocketStream! does respond to the \ct!next:! message as illustrated by \scrref{script:socketStreamNext}.
  520. We consider that we have a server running at port 9999 of our machine that sends a string which size is a multiple of 5.
  521. Right after the connection, we wait 100 milliseconds until the data is received.
  522. Then, we read data in chunks of 5 characters that we display on the Transcript.
  523. So, if the server sends a string with 10 characters \ct!'HelloWorld'!, we will get on the Transcript \ct!Hello! on one line and \ct!World! on a second line.
  524. \section{Tips on Networking Experiments}
  525. In sections related to client-side sockets and socket streams, we use interactions with a web server as an example.
  526. So, we forge an HTTP Get query and send it to the server.
  527. It worth noting that we chose these examples to make experiments straightforward and platform agnostic.
  528. In real scale applications, interactions involving HTTP should be coded using a higher level library such as Zinc HTTP\footnote{\url{http://zn.stfx.eu/zn/index.html}}.
  529. To experiment without dealing with HTTP, we can use Unix utilities.
  530. Readers with a Unix machine (Linux, Mac OS X) or with Cygwin (for Windows) can use \ct!nc! (or netcat), \ct!netstat! and \ct!lsof! for their tests.
  531. \subsection{\ct!nc! (netcat)}
  532. \ct!nc! allows to set up either a client or a server for both TCP (default protocol) and UDP.
  533. It redirects the content of its \ct!stdin! to the other side.
  534. The following snippet show how to send \ct!'Hello from a client'! to a server on the local machine listening on port 9090.
  535. \begin{code}{}
  536. echo Hello from a client | nc 127.0.0.1 9090
  537. \end{code}
  538. The command line below starts a server listening on port 9090 that sends \ct!'Hi from server'! to the first client to connect.
  539. It terminates after the interaction.
  540. \begin{code}{}
  541. echo Hi from server | nc -l 9090
  542. \end{code}
  543. You can keep the server running by means of option \ct!-k!.
  544. But, the string produced by the preceding \ct!echo! is sent only to the first client to connect.
  545. An alternative solution is to make the \ct!nc! server send text you type.
  546. Simply evaluate the following command line.
  547. \begin{code}{}
  548. echo nc -lk 9090
  549. \end{code}
  550. Type in some text in the same terminal where you started the server.
  551. Then, run a client in another terminal.
  552. Your text will be displayed on the client side.
  553. You can repeat these two last actions (type text at the server side, then start client) as many times as needed.
  554. You can even go more interactive by making the connection between a client and a server more persistent.
  555. By evaluating the following command line, the client sends every line (ended with "Enter").
  556. It will terminate when sending the EOF signal (ctl-D).
  557. \begin{code}{}
  558. echo cat | nc -l 9090
  559. \end{code}
  560. \subsection{\ct!netstat!}
  561. This command provides various information on network interfaces and sockets of your computer.
  562. It provides many statics so one need to use appropriate options to filter out useful information.
  563. The following command line allows displaying status of tcp sockets and their addresses.
  564. Note that the port numbers and addresses are separated by a dot.
  565. \begin{code}{}
  566. netstat -p tcp -a -n
  567. \end{code}
  568. \subsection{\ct!lsof!}
  569. The \ct!lsof! command lists all files open in your system.
  570. This of course includes sockets, since everything is a file in Unix.
  571. Why \ct!lsof! is useful, would you say, if we already have \ct!netstat!?
  572. The answer is that \ct!lsof! shows the link between processes and sockets.
  573. So, you can find out sockets related to your program.
  574. The example provided by following command line lists TCP sockets.
  575. The \ct!n! and \ct!P! options force \ct!lsof! to display host addresses and ports as numbers.
  576. \begin{code}{}
  577. lsof -nP -i tcp
  578. \end{code}
  579. \section{Chapter summary}
  580. In this chapter we presented how to use TCP sockets and socket streams to develop both clients and servers.
  581. As mentioned in the introduction, we recommend to use socket streams which are of higher level and provide facility methods.
  582. They were successfully used in projects such as Swazoo and Kom web servers used respectively by AidaWeb and Seaside web frameworks.
  583. Nevertheless, socket streams remain still low-level if you have an application involving different objects distributed over communicating images.
  584. In a such software, developers need to deal with message passing between remote objects by serializing arguments and results.
  585. They will have also to take care of distributed garbage-collection.
  586. An object should not be destroyed if it is referenced by a remote one.
  587. This recurrent not trivial issues are solved by Object-Request Brokers (ORB) such as rST\footnote{http://www.squeaksource.com/rST.html}.
  588. An ORB frees the developer from networking issues and thus allows expressing remote communications simply using messages exchanged between remote objects.
  589. % Noury: Pour pousser le message "Utilisez les SocketStream", est-ce Ben tu pourras remplacer les socket par des SocketStream dans ton code ?
  590. % Reference to a chat instant messages: on Squeaksource: http://www.squeaksource.com/PharoInstantMessenge \ben{maybe it should be moved in another repo}. You can load it using Monticello (Chapter \ja{numChapter}).
  591. %=================================================================
  592. \ifx\wholebook\relax\else\end{document}\fi
  593. %=================================================================