Server.pm
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:7k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Ragnarok Online Assistent
  3. #
  4. #  This software is open source, licensed under the GNU General Public
  5. #  License, version 2.
  6. #  Basically, this means that you're allowed to modify and distribute
  7. #  this software. However, if you distribute modified versions, you MUST
  8. #  also distribute the source code.
  9. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  10. #
  11. #  $Revision: 5803 $
  12. #  $Id: Server.pm 5803 2007-07-08 11:14:47Z vcl_kore $
  13. #
  14. #########################################################################
  15. ##
  16. # MODULE DESCRIPTION: Basic implementation of a TCP/IP server
  17. #
  18. # When writing TCP servers, a significant amount of time is spent in
  19. # handling connection issues (such as establishing connections, client
  20. # multiplexing, etc). This class makes it easier to write a TCP server
  21. # by handling all connection issues for you, so you can concentrate
  22. # on handling the protocol.
  23. #
  24. # You are supposed to create a class which is derived from Base::Server.
  25. # Override the abstract methods onClientNew(), onClientExit() and
  26. # onClientData() (see the API specification).
  27. #
  28. # <h3>Example</h3>
  29. # Here is an example of how to use Base::Server (MyServer.pm):
  30. # <pre class="example">
  31. # package MyServer;
  32. #
  33. # use strict;
  34. # use Base::Server;
  35. # use base qw(Base::Server);
  36. #
  37. # sub onClientNew {
  38. #     my ($self, $client, $index) = @_;
  39. #     print "Client $index connected.n";
  40. # }
  41. #
  42. # sub onClientExit {
  43. #     my ($self, $client, $index) = @_;
  44. #     print "Client $index disconnected.n";
  45. # }
  46. #
  47. # sub onClientData {
  48. #     my ($self, $client, $data, $index) = @_;
  49. #     print "Client $index sent the following data: $datan";
  50. # }
  51. #
  52. # 1;
  53. # </pre>
  54. # And in the main script you write:
  55. # <pre class="example">
  56. # use strict;
  57. # use MyServer;
  58. #
  59. # my $port = 1234;
  60. # my $server = new MyServer($port);
  61. # while (1) {
  62. #     # Main loop
  63. #     $server->iterate;
  64. # }
  65. # </pre>
  66. #
  67. # <h3>The client object</h3>
  68. # See @MODULE(Base::Server::Client) for more information about how to use $client.
  69. package Base::Server;
  70. use strict;
  71. use warnings;
  72. no warnings 'redefine';
  73. use IO::Socket::INET;
  74. use Base::Server::Client;
  75. use Utils::ObjectList;
  76. use Utils::Exceptions;
  77. ################################
  78. ### CATEGORY: Constructor
  79. ################################
  80. ##
  81. # Base::Server Base::Server->new([int port, String bind])
  82. # port: the port to bind the server socket to. If unspecified, the first available port (as returned by the operating system) will be used.
  83. # bind: the IP address to bind the server socket to. If unspecified, the socket will be bound to "localhost". Specify "0.0.0.0" to not bind to any address.
  84. #
  85. # Start a server at the specified port and IP address.
  86. #
  87. # Throws SocketException if the server socket cannot be created.
  88. sub new {
  89. my $class = shift;
  90. my $port = (shift || 0);
  91. my $bind = (shift || 'localhost');
  92. my %self;
  93. $self{BS_server} = IO::Socket::INET->new(
  94. Listen => 5,
  95. LocalAddr => $bind,
  96. LocalPort => $port,
  97. Proto => 'tcp',
  98. ReuseAddr => 1);
  99. if (!$self{BS_server}) {
  100. SocketException->throw($@);
  101. }
  102. $self{BS_host} = $self{BS_server}->sockhost;
  103. $self{BS_port} = $self{BS_server}->sockport;
  104. $self{BS_clients} = new ObjectList();
  105. return bless %self, $class;
  106. }
  107. sub createFromSocket {
  108. my ($class, $socket) = @_;
  109. my %self = (
  110. BS_server  => $socket,
  111. BS_clients => new ObjectList()
  112. );
  113. return bless %self, $class;
  114. }
  115. sub DESTROY {
  116. my ($self) = @_;
  117. $self->{BS_server}->close if ($self->{BS_server});
  118. }
  119. ################################
  120. ### CATEGORY: Methods
  121. ################################
  122. sub clients {
  123. return $_[0]->{BS_clients}->getItems();
  124. }
  125. ##
  126. # String $BaseServer->getHost()
  127. # Returns: an IP address in textual form.
  128. #
  129. # Get the IP address on which the server is started.
  130. sub getHost {
  131. return $_[0]->{BS_host};
  132. }
  133. ##
  134. # int $BaseServer->getPort()
  135. # Returns: a port number.
  136. #
  137. # Get the port on which the server is started.
  138. sub getPort {
  139. return $_[0]->{BS_port};
  140. }
  141. ##
  142. # void $BaseServer->iterate()
  143. #
  144. # Handle connection issues. You should call this function in your
  145. # program's main loop.
  146. sub iterate {
  147. my ($self, $timeout) = @_;
  148. my $serverFD = fileno($self->{BS_server});
  149. # Generate the bit field for select();
  150. my $rbits = '';
  151. vec($rbits, $serverFD, 1) = 1;
  152. my $clients = $self->{BS_clients}->getItems();
  153. foreach my $client (@{$clients}) {
  154. if (!$client->getSocket()->connected) {
  155. $self->_exitClient($client, $client->getIndex());
  156. } else {
  157. my $fd = $client->getFD();
  158. vec($rbits, $fd, 1) = 1;
  159. }
  160. }
  161. if (@_ == 1) {
  162. $timeout = 0;
  163. } elsif ($timeout == -1) {
  164. $timeout = undef;
  165. }
  166. if (select($rbits, undef, undef, $timeout) > 0) {
  167. # Checks whether new clients want to connect.
  168. if (vec($rbits, $serverFD, 1)) {
  169. $self->_newClient();
  170. }
  171. # Check for connection changes in clients.
  172. foreach my $client (@{$clients}) {
  173. my $fd = $client->getFD();
  174. if (vec($rbits, $fd, 1)) {
  175. # Incoming data from client.
  176. my $data;
  177. $client->getSocket()->recv($data, 32 * 1024, 0);
  178. if (!defined($data) || length($data) == 0) {
  179. # Client disconnected.
  180. $self->_exitClient($client, $client->getIndex());
  181. } else {
  182. $self->onClientData($client, $data, $client->getIndex());
  183. }
  184. }
  185. }
  186. }
  187. }
  188. ##
  189. # boolean $BaseServer->sendData(Base::Server::Client client, Bytes data)
  190. #
  191. # This function is obsolete. Use $BaseServerClient->send() instead.
  192. sub sendData {
  193. my ($self, $client) = @_;
  194. return $client->send($_[2]);
  195. }
  196. ####################################
  197. ### CATEGORY: Abstract methods
  198. ####################################
  199. ##
  200. # abstract void $BaseServer->onClientNew(Base::Server::Client client, int index)
  201. # client: a client object (see overview).
  202. # index: the client's index (same as $client->getIndex).
  203. # Requires: defined($client)
  204. #
  205. # This method is called when a new client has connected to the server.
  206. sub onClientNew {
  207. }
  208. ##
  209. # abstract void $BaseServer->onClientExit(Base::Server::Client client, int index)
  210. # client: a client object (see overview).
  211. # index: the client's index (same as $client->getIndex).
  212. # Requires: defined($client)
  213. #
  214. # This method is called when a client has disconnected from the server.
  215. sub onClientExit {
  216. }
  217. ##
  218. # abstract void $BaseServer->onClientData(Base::Server::Client client, Bytes data, int index)
  219. # client: a client object (see overview).
  220. # data: the data this client received.
  221. # index: the client's index (same as $client->getIndex).
  222. # Requires: defined($client) && defined($data)
  223. #
  224. # This method is called when a client has received data.
  225. sub onClientData {
  226. }
  227. ##############
  228. # Private
  229. ##############
  230. # Accept connection from new client
  231. sub _newClient {
  232. my ($self) = @_;
  233. my $sock = $self->{BS_server}->accept();
  234. $sock->autoflush(0);
  235. my $fd = fileno($sock);
  236. my $host;
  237. $sock->peerhost if ($sock->can('peerhost'));
  238. my $client = new Base::Server::Client($sock, $host, $fd);
  239. my $index = $self->{BS_clients}->add($client);
  240. $client->setIndex($index);
  241. $self->onClientNew($client, $index);
  242. }
  243. # A client disconnected
  244. sub _exitClient {
  245. my ($self, $client, $index) = @_;
  246. $self->onClientExit($client, $index);
  247. $self->{BS_clients}->remove($client);
  248. }
  249. 1;