tag:blogger.com,1999:blog-43304274538852667052024-02-20T16:21:31.494-08:00Ingenieros De SoftwareOpiniones, notas , ideas y codigo (salvo damas bonitas, que mas se puede pedir ?)Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-4330427453885266705.post-19329273969011689042011-02-26T03:56:00.001-08:002011-02-26T03:56:03.506-08:00<span xmlns=''><p style='text-align: center; margin-left: 18pt'><span style='font-family:Times New Roman'><strong>Learning through Application<br /></strong></span></p><p style='text-align: center; margin-left: 18pt'><span style='font-family:Times New Roman'><strong>Victor R. Basili<br /></strong></span></p><p style='text-align: center; margin-left: 18pt'><span style='font-family:Times New Roman'><strong>University of Maryland and Fraunhofer Center - Maryland</strong><br /> </span></p><p><span style='font-family:Times New Roman'>The good news is that empirical studies have finally become recognized as an important component of the software engineering discipline. One sees more and more empirical studies and experiments in the literature. The bad news is that these studies are often used as confirming or not confirming the effectiveness of some method, technique, or tool, rather than as part of the process of discovery process. The experiment is an add-on, we do the study after the concept is considered complete, rather than applying the method, technique or tool and learning from the application about how to evolve the concept. This is the basis of the scientific method; theories are tested and evolved over time. In the software engineering discipline, where the theories and models are still in the formative stages and processes are applied by humans a part of a creative process, observing the application or performing exploratory studies become an important step in the evolution of the discipline. <br /></span></p><p><span style='font-family:Times New Roman'>Software engineering has several characteristics that that distinguish it from other disciplines. Software is developed, in the creative, intellectual sense, rather than produced in the manufacturing sense. Software processes are development processes not production processes. They are not replicated over and over again. This aspect of the discipline is probably the most important. This affects greatly how we learn. We need to always be on the lookout for the effect of context variables. Since it a human-based discipline there will always be variation in study results and we will never be able to control or even identify all the context variables. It creates a need for continual experimentation as we must understand how to modify and tailor processes for people.<br /></span></p><p><span style='font-family:Times New Roman'>The context issue is more than just the people; all software is not the same and all software development environments are different. One consequence of this is that process is a variable, goals are variable, etc. That is, we need to select the right processes for the right goals for the environment we are analyzing. So, before we decide how to study something we need to know something about the environment and the characteristics of the thing we are about to build. <br /></span></p><p><span style='font-family:Times New Roman'>Also, the software engineering discipline is still quite immature in the sense that there is a lack of models that allow us to reason about the process, the product and their relationships. This compounds the non-visible nature of software. It intensifies the need to learn from the application of the ideas in different situations and the requirement to abstract from what we see. <br /></span></p><p><span style='font-family:Times New Roman'>Add to this the fact that developing models of our experiences for future use (reuse) requires additional resources in the form of money, organization support, processes, people, etc. Building models, taking measurements, experimenting to find the most effective technologies, and feeding back information for corporate learning, cost both time and money. These activities are not a by-product of software development. If these activities are not explicitly supported, independent of the product development, they will not occur and we will not make quality improvements in the development process.<br /></span></p><p><span style='font-family:Times New Roman'>All this makes good experimentation difficult and expensive. Experiments can only be confirmatory in the small and are subject to problems in understanding scale-up, the integration of one process with another, the understanding of the effect of context variables, etc. <br /></span></p><p><span style='font-family:Times New Roman'>I believe we need to focus more attention on informal exploratory studies that provide insights, coupled, when appropriate, with more formal empirical studies to test out pieces of the whole that can be added to the tapestry that helps make the discipline clear. I believe that the study of the software engineering discipline is exploratory and evolutionary. It follows the scientific method but because of its nature, real experiments are not always possible or useful. <br /></span></p><p><span style='font-family:Times New Roman'>I like to say that the study of software engineering is a laboratory science; and it is a big science. So the laboratory is quite grand and we need methods that support the exploratory nature of this big science. The discipline cannot be understood only by analysis. We need to learn from application whether relationships hold, how they vary, what the limits of various technologies are, so we can know how to configure process to develop software better.<strong><br /> </strong></span></p><p><span style='font-family:Times New Roman'>We need to take advantage of all opportunities to explore various ideas in practice, e.g., test its feasibility, find out if humans can apply it, understand what skills are required to apply it, test its interaction with other concepts. Based upon that knowledge, we need to refine and tailor it to the application environment in which we are studying it so it can be easily transferred into practice. So, we need to try out our ideas in practice and evolve them, even before we can build models. We are an exploratory science – we are more dependent on empirical application of methods and techniques than many disciplines and we need to share the results.<br /></span></p><p><span style='font-family:Times New Roman'>Time is an important aspect in the application of the scientific method to software engineering; there needs to be many applications of a process, in different environments, with each application providing a better understanding of the concepts and their interaction. Over time all context variables need to be considered and many of them don't even pop up until we have seen the application of the approach in practice a by different people in different sites.</span></p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com2tag:blogger.com,1999:blog-4330427453885266705.post-78153680072225575612011-02-26T03:54:00.001-08:002011-02-26T03:54:50.359-08:00<span xmlns=''><h1>Context Counts: Position Paper for SEMAT<br /></h1><p><br /> </p><p>By Scott W. Ambler<br /></p><p>Chief Methodologist/Agile, IBM Rational<br /></p><p><br /> </p><p>I believe that for the SEMAT endeavor to be successful that as a community we need to come to a consensus regarding both our philosophical foundation and our scope. Ivar Jacobson, Bertrand Meyer, and Richard Soley have made good inroads towards addressing these issues [1, 2] but we still have some work ahead of us. <br /></p><p><br /> </p><p>My main points:<br /></p><ol><li>Practices are contextual, never "best"<br /></li><li>We must go beyond practices<br /></li><li>We're more successful than we think<br /></li><li>We need to reuse existing resources<br /></li></ol><p><br /> </p><h1>1. Practices are Contextual, never "Best"<br /></h1><p>We must define the context in which practices will be applied, because the context determines the applicability of the practice as well as how it is tailored. An approach which works well for a medium-sized co-located team in a regulatory compliance situation is likely to fare poorly for a small distributed team developing an informational website. Furthermore context is particularly important for the research behind the practices, because without a clear indication as to the context in which the practice was evaluated it will be very difficult for practitioners to identify which strategies are best suited for them. At IBM Rational we've been applying the 1+8 scaling factors of the Agile Scaling Model (ASM) [3] to help communicate the context faced by project teams. A tenth factor, paradigm, is implied. These factors are:<br /></p><ol><li><em>Life cycle scope</em>. Is your focus on the construction life cycle? On the delivery life cycle? On the full system life cycle (include project identification activities, production, and retirement)? On the enterprise IT life cycle? <br /></li><li><em>Team size</em>. The strategy followed by a team of 7 people will be different than a team of 25, than a team of 50, than a team of 200, and so on. <br /></li><li><em>Geographical distribution</em>. A co-located team will work differently than a team distributed across several cubes on the same floor, which in turn works differently than a team distributed across different locations within the same city, which works differently than an internationally distributed team. <br /></li><li><em>Regulatory compliance</em>. A team which needs to conform to the FDA CFR 21 regulations will work differently than a team which doesn't need to do so. A team working in an ISO 9000 compliant organization will work differently than a team working in another organization. <br /></li><li><em>Domain complexity</em>. A team addressing a very straightforward problem, such as developing a data entry application or an informational Web site, will work differently than a team building an air traffic control system. <br /></li><li><em>Organizational distribution</em>. A team made up of people working for the same division of an organization works differently than a team made up of people from different divisions which in turn works differently than teams made up of people from several divisions. Teams with on-site contractors work differently than teams where some of the work is outsourced to an external organization. <br /></li><li><em>Technical complexity</em>. Teams building new systems from scratch will work differently than those working with legacy systems and data. Teams working with a single technology platform will work different than those working with several platforms. Teams building only software will work differently than systems engineering teams building both software and hardware. <br /></li><li><em>Organizational complexity</em>. Teams working in an organization with a flexible culture will work differently than teams working in one with a rigid culture. Teams working in organizations with homogenous cultures will work different than teams in heterogeneous cultures. Teams working in organizations with cultures that are pro-IT will work differently than teams in organizations where this isn't the case. <br /></li><li><em>Enterprise discipline</em>. Teams working in organizations with effective enterprise disciplined (enterprise architecture, portfolio management, governance, asset management, administration, …) will work differently in organization where this isn't the case. <br /></li><li><em>Paradigm</em>. Teams following an agile paradigm will work differently than those following a traditional/serial paradigm which will work differently than those following an ad-hoc paradigm.<br /></li></ol><p><br /> </p><p>These factors affect how you address kernel elements. For example, I'll be so bold as to assert that there will be some sort of requirements elicitation element in the kernel. I recently wrote about how to scale agile requirements strategies by working through the ASM scaling factors and describing how each factor affects your approach [4]. The various factors affected the timing of elicitation, the specification strategy, the tooling strategy, the collaboration strategy, and other aspects of requirements work. This is just one example, but the same holds true for architecture, quality, development, management activities, and other potential kernel elements. The SEMAT kernel needs to recognize the contextual factors faced by organizations and of individual development teams.<br /></p><p><br /> </p><p><br /> </p><h1>2. We Must Go Beyond Practices<br /></h1><p>Although there's been a lot of discussion around practices we've also recognized that there is a lot more to it than that. At IBM Rational we've found that to be successful you must address the "5 Ps" of IT [5]: <br /></p><ol><li><em>People</em>. People and the way they work together have a greater effect on the outcomes of a project than the processes they're following or the products (tools and technologies) that they're using. People issues include having visible executive sponsorship, building an environment of trust, empowering staff, focusing on leadership as well as management, recognizing that the primary gating factor when improving processes is people's ability to absorb change, and promoting a cross-discipline strategy at both the team and individual levels. <br /></li><li><em>Principles</em>. We've found both internally within IBM as well as with many of our customers that there is a need to define a common set of principles to provide a consistent foundation to enable effective teamwork and continuous process improvement. These principles help to guide people's decisions when their processes and practices don't directly address the situation which they find themselves in.<br /></li><li><em>Practices</em>. A practice is a self-contained, deployable component of a process. <br /></li><li><em>Products</em>. This includes the technologies – such as databases, application servers, networks, and client platforms – and tools such as integrated development environments, testing tools, and project planning tools used to create solutions for stakeholders. <br /></li><li><em>Processes</em>. The previous 4Ps do not exist in a vacuum, we need some sort of glue to help piece all of this together. Minimally this glue is a lifecycle although more often than not it is a full process or method. <br /></li></ol><p><br /> </p><p>I believe that these five issues must be addressed by the scope definition of the SEMAT initiative.<br /></p><p><br /> </p><h1>3. We're More Successful Than We Think<br /></h1><p>My experience, backed up by recent surveys [6], shows that the way that organizations define project success vary based on their context, and as a result I'm not convinced that our track record is as bad as we think it is. My surveys which ask people how their organization actually defines success reports higher success rates than studies which enforce their own definition of success on respondents. I am convinced that a definition of on time, on budget, and on scope compared against up-front promises is clearly not appropriate for most project teams. Perhaps one thing that the SEMAT initiative can do is start educating people on the futility of this strategy. If the people applying the SEMAT kernel cannot reasonably measure success, how can SEMAT in turn ever be seen as successful itself?<br /></p><p><br /> </p><p><br /> </p><h1>4. We Need to Reuse Existing Resources<br /></h1><p>There is a significant amount of practice and process-oriented intellectual property (IP) available via open source and similar licensing strategies. For example, the Eclipse Process Framework (EPF) at <a href='http://www.eclipse.org/epf/'>www.eclipse.org/epf/</a> includes both process tooling and IP which we could choose to leverage free of charge. This IP includes descriptions of Extreme Programming (XP), Scrum, the Open Unified Process (OpenUP), various agile practices, and other material. Of course there are many more examples of process/practice IP available under Creative Commons licenses. How can SEMAT be successful if we strive to reinvent the wheel?<br /></p><p><br /> </p><h1>5. References<br /></h1><ol><li>Jacobson, I. Meyer, B. and Soley, R. (2009). <em>The SEMAT Charter – A Proposal</em>. <a href='http://sematblog.wordpress.com/2009/12/19/the-semat-charter-a-proposal/'>http://sematblog.wordpress.com/2009/12/19/the-semat-charter-a-proposal/</a><br /> </li><li>Jacobson, I. Meyer, B. and Soley, R. (2009). <em>What is the scope of the kernel?</em><br /> <a href='http://sematblog.wordpress.com/2009/12/18/what-is-the-scope-of-the-kernel/'>http://sematblog.wordpress.com/2009/12/18/what-is-the-scope-of-the-kernel/</a><br /> </li><li>Ambler, S.W. (2009). <em>The Agile Scaling Model (ASM): Adapting Agile Methods for Complex Environments</em>. <a href='ftp://ftp.software.ibm.com/common/ssi/sa/wh/n/raw14204usen/RAW14204USEN.PDF'>ftp://ftp.software.ibm.com/common/ssi/sa/wh/n/raw14204usen/RAW14204USEN.PDF</a><br /> </li><li>Ambler, S.W. (2009). <em>Agile Requirements at Scale</em>. <a href='https://www.ibm.com/developerworks/mydeveloperworks/blogs/ambler/entry/agile_requirements_at_scale'>https://www.ibm.com/developerworks/mydeveloperworks/blogs/ambler/entry/agile_requirements_at_scale</a><br /> </li><li>Ambler, S.W. (2010). <em>Scaling Agile: An Executive Guide</em>. To be published Feb 1 at <a href='http://www.ibm.com'>www.ibm.com</a>. <br /></li></ol><p>Ambler, S.W. (2006). <em>Surveys Exploring the Current State of Information Technology Practices.</em><br /> <a href='http://www.ambysoft.com/surveys/'>http://www.ambysoft.com/surveys/</a><br /> </p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-5873061807309750612011-01-23T13:14:00.001-08:002011-03-24T02:46:48.551-07:00Algo mas sobre SOCKETS y Ports<span xmlns=""><p><br /> </p><p><br /> </p><p><br /> </p><p style="TEXT-ALIGN: center"><span style="font-size:26;"><strong>Manual del<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-size:26;"><strong>Lenguaje de programación<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-size:26;"><strong>C#<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-size:26;"><strong>Parte VI-A<br /></strong></span></p><p style="TEXT-ALIGN: center"><br /> </p><p style="TEXT-ALIGN: center"><span style="font-size:26;"><strong>Sockets y Ports<br /></strong></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><br /> </p><p><br /> </p><p> </p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448778"><span style="font-family:Verdana;font-size:10;">OBJETIVO DEL MANUAL 3</span><br /></a></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448779"><span style="font-family:Verdana;font-size:10;">OBJETIVO DEL MANUAL 3</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448780"><span style="font-family:Verdana;font-size:10;">Sockets y Ports 3</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448781"><span style="font-family:Verdana;font-size:10;">SOCKET 4</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448782"><span style="font-family:Verdana;font-size:10;">¿Con que contamos en C#? 6</span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448783"><span style="font-family:Verdana;font-size:10;">Procesos de un solo thread y sincrónicos.- 7</span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448784"><span style="font-family:Verdana;font-size:10;">Procesos de mas de un thread y asincrónicos.- 8</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448785"><span style="font-family:Verdana;font-size:10;">Usar un socket para comunicaciones con el protocolo HTTP 8</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448786"><span style="font-family:Verdana;font-size:10;">El protocolo HTTP 8</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448787"><span style="font-family:Verdana;font-size:10;">Y lo ejecutamos, vemos la salida de texto que se muestra a continuación: 16</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448788"><span style="font-family:Verdana;font-size:10;">Usar sockets para armar un programa de mensajería entre pares (chat) 18</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448789"><span style="font-family:Verdana;font-size:10;">Codigo en Form1.cs 20</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448790"><span style="font-family:Verdana;font-size:10;">Código en program.cs 21</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448791"><span style="font-family:Verdana;font-size:10;">Código en Talker.cs 23</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448792"><span style="font-family:Verdana;font-size:10;">Como ejecutar la aplicación 32</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448793"><span style="font-family:Verdana;font-size:10;">Sockets y Ports 33</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=587306180730975061#_Toc276448794"><span style="font-family:Verdana;font-size:10;">El protocolo FTP 33</span></a><br /></p><p><br /> </p><p><br /> </p><p><h1>OBJETIVO DEL MANUAL<br /></h1><p></p><p><br /> </p><h2>Sockets y Ports<br /></h2><p>Un Socket es una abstracción.-<br /></p><p>Representa un punto de intercomunicación entre dos procesos (por ejemplo cliente y servidor). Los procesos pueden estar en el mismo host, nodo o computadora o en nodos diferentes.-<br /></p><p>En un host pueden correr diferentes procesos brindando diferentes servicios. Por ejemplo servicios de HTTP, de Telnet, de FTP, de SMTP, etc. Cada uno de estos procesos tiene una dirección que lo identifica unívocamente respecto de los otros. Esta dirección se llama PORT.<br /></p><p>Generalmente el servicio de HTTP se brinda en el port 80, el de Telnet en el 23, FTP en el 21 y SMTP en el 25. Decimos entonces que un PORT es una dirección relativa. Identifica al proceso pero no identifica al host en el que corre dicho proceso.<br /></p><p>En una red TCP/IP como Internet cada host tiene una identificación única llamada número IP.<br /></p><p>Un SOCKET es un número IP + un PORT. Por lo tanto es una dirección absoluta ya que identifica unívocamente un proceso en toda la red. </p><p><br /> </p><h2>SOCKET<br /></h2><p>La especificación Windows Sockets define una interfaz de programación en Windows basada en el paradigma de sockets del BSD (Berkeley Software Distribution).-<br /></p><p>Esta biblioteca, escrita en lenguaje C por ingenieros, profesores y estudiantes de la Universidad de Berkeley, fue pensada para la comunicación entre procesos que se ejecutan en la misma computadora o en computadoras de una misma red.-<br /></p><p>EL software fue escrito originalmente como una API (Application Programming Interface) y el código que figura a continuación es un pequeño esqueleto que muestra como es la secuencia de inicio y cierre de un proceso de comunicación, pensando en un solo thread de ejecución:<br /></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <sys/types.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <sys/socket.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <netinet/in.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <arpa/inet.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdio.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdlib.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <strings.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int main()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Inicio<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int32_t i32SocketFD = socket(AF_INET, SOCK_STREAM, 0);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(0 == i32SocketFD)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("no se puede crear el socket");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>struct sockaddr_in stSockAddr;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bzero(&stSockAddr, sizeof(stSockAddr));<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_family = AF_INET;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_port = htons(1100);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Enlace<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(-1 == bind(i32SocketFD,(struct sockaddr*) &stSockAddr, sizeof(stSockAddr)))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error: bind fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Escucha<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(-1 == listen(i32SocketFD, 10))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error: listen fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>for(; ;)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int32_t i32ConnectFD = accept(i32SocketFD, NULL, NULL);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(0 > i32ConnectFD)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error accept fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// acá es donde se debe escribir el código especifico ...<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>…..<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//cierre<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>shutdown(i32ConnectFD, 2);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>close(i32ConnectFD);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><h2>¿Con que contamos en C#?<br /></h2><p>En C#, encontramos la funcionalidad de esta especificación, encapsulada en una clase llamada Socket, que es la que provee los métodos para la comunicación a través de la red así como la transferencia (sincrónica o asíncrona de datos).-<br /></p><p>La clase Socket se encarga de proveer métodos y propiedades para la comunicación en red.-<br /></p><p>Lo realmente interesante de esta clase es que encapsula la complejidad de la comunicación y una vez establecida el manejo de lo entrante y saliente se hace manejando flujos (streams).-<br /></p><p>Estos flujos de comunicación pueden ser sincrónicos o asíncronos.-<br /></p><h3>Procesos de un solo thread y sincrónicos.-<br /></h3><p>Igual que en el ejemplo en lenguaje C visto al inicio de este manual, para procesos de un solo thread podemos utilizar los métodos específicos para modo de operación asíncrona: Listen(), Accept(), Bind(), Send() y Receive().-<br /></p><h4>Protocolo TCP<br /></h4><p>Estos métodos se utilizan en protocolos orientados a conexión (connection-oriented) como por ejemplo TCP.-<br /></p><p>En este caso el servidor de la comunicación puede escuchar los pedidos con el método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasslistentopic.htm">Listen</a> .-<br /></p><p>EL método Accept() procesa cualquier pedido de conexión entrante y retorna un Socket que es el que se utilizara para comunicar datos con el host remoto.-<br /></p><p>Es este Socket el que se usa para llamar a los métodos <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasssendtopic.htm">Send</a>() o <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassreceivetopic.htm">Receive</a>().-<br /></p><p>Como en el caso general se desea indicar la dirección IP y el numero de puerto, se debe llamar al método Bind(), previo a llamar a Listen().-<br /></p><p>En caso de no seguir esta secuencia, el proveedor del servicio subyacente asignara estos valores por nosotros. Es posible luego obtener la dirección IP y port asignados a nuestro Socket, del modo recién indicado.-<br /></p><p>En el caso de querer conectarse a un servidor que esta escuchando requisiciones, se debe llamar al método Connect() y luego utilizar Send() y Receive() para envío y recepción de datos.-<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// crear un socket<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// enlazar el socket que escucha<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint ep = new IPEndPoint(hostIP, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listenSocket.Bind(ep);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// escuchar<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listenSocket.Listen(backlog);<br /></strong></span></p><p><br /> </p><h4>Protocolo UDP<br /></h4><p>Si usamos un protocolo como UDP (protocolo sin conexión: connectionless), entonces no es necesario "escuchar" para conectarse. El método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassreceivefromtopic.htm">ReceiveFrom</a>() es el que debe usarse para recibir los datagramas entrantes y el método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasssendtotopic.htm">SendTo</a>() es el que debe usarse para el envio de datagramas al host remoto.<br /></p><h3>Procesos de mas de un thread y asincrónicos.-<br /></h3><p><span style="font-family:Verdana;font-size:9;">Para procesar comunicaciones utilizando threads separados, existen una serie de mtodos pensados al efecto, es decir en un modo de operacion asincrono.-<br /></span></p><h4>Protocolo TCP<br /></h4><p>Cuando se utilizan protocolos orientados a la conexión (connection-oriented) como TCP, entonces debe utilizar los métodos Socket(), <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginconnecttopic.htm">BeginConnect</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendconnecttopic.htm">EndConnect</a>() para comenzar las tareas de conexiones con el server que atiende los pedidos.-<br /></p><p>El asincronismo en el envío y la recepción de datos (en los casos donde trabajamos con mas de un thread) necesita del uso de los métodos específicos de comunicación asincrónica. Estos son: <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginsendtopic.htm">BeginSend</a>(),<a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendsendtopic.htm">EndSend</a>() , <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginreceivetopic.htm">BeginReceive</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendreceivetopic.htm">EndReceive</a>(). Los pedidos de conexión entrante los debe procesar con los métodos: <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginaccepttopic.htm">BeginAccept</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendaccepttopic.htm">EndAccept</a>().<br /></p><p>Si estamos usando UDP entonces los métodos adecuados son para enviar datagramas son <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginsendtotopic.htm">BeginSendTo</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendsendtotopic.htm">EndSendTo</a>() y para la recepción se debe usar <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginreceivefromtopic.htm">BeginReceiveFrom</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendreceivefromtopic.htm">EndReceiveFrom</a>().<br /></p><h1>Usar un socket para comunicaciones con el protocolo HTTP<br /></h1><p>El ejemplo siguiente utiliza una clase Socket para enviar y recibir respuestas de un servidor HTTP.<br /></p><p>Pensemos en un servidor WEB que esta corriendo en algún punto de la red.<br /></p><p>El modo en el que escribimos el código requiere de algunos conceptos de cómo trabaja el protocolo HTTP, damos un repaso que consideramos adecuado.-<br /></p><h2>El protocolo HTTP<br /></h2><p>El Protocolo de Transferencia de Hipertexto (Hypertext Transfer Protocol) es un protocolo para comunicación entre un nodo cliente y otro nodo servidor.-<br /></p><p>Su uso central es en la WEB, pero aclaremos que un servidor HTTP, puede recibir pedidos y enviar información sin necesidad de la existencia de browsers. Es decir es un mecanismo de comunicación que puede llegar a utilizarse en procesos puramente batch , no solo para interactivos.-<br /></p><p>El protocolo esta montado sobre el servicio de conexión TCP/IP.<br /></p><p>HTTP se basa en sencillas operaciones de solicitud/respuesta.<br /></p><p>Un cliente establece una conexión con un servidor y envía un mensaje con los datos de la solicitud.-<br /></p><p>El servidor responde con un mensaje similar, que contiene el estado de la operación y su posible resultado.-<br /></p><p>La primera parte de una transacción HTTP es cuando un cliente crea y envia una solicitud al servidor.<br /></p><p>Por ejemplo:<br /></p><p>GET /index.html /HTTP 1.1<br /></p><p>Es una pedido absolutamente correcto para un servidor HTTP activo<br /></p><p>Existen tres verbos básicos que un cliente puede utilizar para dialogar con el servidor: GET, para recoger un objeto, POST, para enviar información al servidor y HEAD, para solicitar las características de un objeto (por ejemplo, la fecha de modificación de un documento HTML).<br /></p><p>Todas las operaciones pueden adjuntar un objeto o recurso sobre el que actúan; cada objeto Web (documento HTML, fichero multimedia o aplicación CGI) es conocido por su URL (Uniform resources location podría concebirse como la extensión del concepto de nombre completo de un archivo (path)).<br /></p><p>Cada operación HTTP implica una conexión con el servidor, que es liberada al término de la misma. (Esa es la verdadera esencia de Internet ¡!)<br /></p><p>Es decir, en una operación se puede recoger un único objeto y no se mantienen estados.<br /></p><p>Cada petición de un cliente a un servidor no es influida por las transacciones anteriores. El servidor trata cada petición como una operación totalmente independiente del resto.<br /></p><p>El acceso a los servidores HTTP se realiza a través de las URLs, que empaquetan toda la información necesaria para localizar un determinado recurso en Internet. Cuando el servidor recibe una URL, a través del protocolo HTTP, la decodifica y devuelve al cliente la información correspondiente, que puede ser de dos tipos, en función del contenido de la URL:<br /></p><p>Información estática: que se publica a base de situar los ficheros que la contienen en unos directorios especiales que define cada servidor. Este es el procedimiento que se ha utilizado hasta ahora.<br /></p><p>Información dinámica: en este caso, el servidor HTTP arranca una aplicación utilizando la propia URL como parámetro de ejecución. El resultado de la ejecución de la aplicación será devuelto al cliente<br /></p><p>El término 'información dinámica' se amplia cada vez más, a medida que se dispone de nuevas aplicaciones y tecnologías de publicación de información.<br /></p><p>A través de estas nuevas tecnologías, es posible generar vistas a través del Web de elementos tan dispares como hojas de cálculo, bases de datos, agendas de reuniones, correos electrónicos e incluso periódicos completos, que se actualizan automáticamente en función de los cambios en el contenido de información original.<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.IO;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net.Sockets;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public class mySocket<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static Socket connectSocket(string server, int port)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket s = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPHostEntry iphe = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>iphe = Dns.Resolve(server);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Esta iteracion a traves de la lista de direcciones ( AddressList) es para obtener la<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//llamada familia de direcciones ( AddressFamily) soportada.Esto evitara una excepcion en el caso<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//en que la dirección IP no sea compatible con dicha familia.-<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>foreach (IPAddress ipad in iphe.AddressList)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint ipe = new IPEndPoint(ipad, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket tmpS =<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>tmpS.Connect(ipe);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (tmpS.Connected)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>s = tmpS;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (SocketException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("SocketException !!!");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Origen : " + e.Source);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Mensaje : " + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (Exception e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Exception atrapada!!!");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Origen : " + e.Source);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Mensaje : " + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return s;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// este método consulta el contenido de la pagina Home del servidor indicado.<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// y muestra el contenido recibido<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static string socketSendReceive(string server, int port)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>//Preparamos para escribir al server<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Encoding ASCII = Encoding.ASCII;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string Get = "GET / HTTP/1.1\r\nHost: " + server +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"\r\nConnection: Close\r\n\r\n";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Byte[] ByteGet = ASCII.GetBytes(Get);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Byte[] RecvBytes = new Byte[256];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String strRetPage = null;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Ahora creamos un socket como conneccion con el server y el port indicado<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket s = connectSocket(server, port);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (s == null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return ("Conneccion fallida");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Ahi viaja el pedido al servidor.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>s.Send(ByteGet, ByteGet.Length, 0);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Aca viene la respuesta de la pagina home del server<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Leer los primeros 256 bytes.Esto lo determina el uso de<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//RecvBytes.Length en el método Receive<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = "Pagina Default HTML en el " + server + ":\r\n";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>while (bytes > 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return strRetPage;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public static void Main(string[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string host;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int port = 91;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (args.Length == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// si no hay server indicado, usamos el nombre del host.<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>host = Dns.GetHostName();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>host = args[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string result = socketSendReceive(host, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine(result);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p>Vamos a hacer la prueba de este programa conectándolo contra un server WEB TOMCAT.<br /></p><p><br /> </p><p>En mi equipo, como se observa, esta levantado en el puerto 8088.-<br /></p><p>Si ejecuto el programa, colocando como parámetro en la línea de ejecución del programa, esta dirección.<br /></p><p><br /> </p><h1><span style="font-size:10;">Y lo ejecutamos, vemos la salida de texto que se muestra a continuación:<br /></span></h1><p><br /> </p><p>Por supuesto que es mejor verla con el browser ¡!<br /></p><p><br /> </p><p><h1>Usar sockets para armar un programa de mensajería entre pares (chat)<br /></h1><p></p><p>Vamos a construir una aplicación Windows que nos entregue una interfaz simple para comunicación. Queremos que sea un contenedor con dos paneles.<br /></p><p>Uno que me muestre los mensajes que recibo y el otro que me permita escribir mensajes.-<br /></p><p>La propia aplicación trabajara de dos modos diferenciados dependiendo de cómo se la invoque en la llamada. En un caso será servidor y en otro cliente.-<br /></p><p>Alcanza con solo servidor para atender múltiples clientes.-<br /></p><p>El esquema que armamos es el de "estrella". Es decir tal como armamos la aplicación todos los clientes pueden hablar con el servidor, pero no entre si.-<br /></p><p>Una variante de este modo en el que el servidor atrape el pedido y lo derive u otro cliente de la red es relativamente sencillo de hacer basado en la tecnología mostrada en este ejemplo.-<br /></p><p><br /> </p><p>Se habrá creado un proyecto con una serie de componentes como muestra el grafico<br /></p><p><br /> </p><p>En este tipo de aplicaciones dentro del Form (Form1.cs), la IDE de .NET escribe algunos códigos de inicialización que no queremos para nuestro caso.-<br /></p><h2>Codigo en Form1.cs<br /></h2><p>Ingrese a código de Form1.Designer.cs y reemplácelo por el código que figura a continuación:<br /></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>partial class Form1<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// <summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// Required designer variable.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// </summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private System.ComponentModel.IContainer components = null;<br /></strong></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>#region Windows Form Designer generated code<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// <summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// Required method for Designer support - do not modify<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// the contents of this method with the code editor.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// </summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private void InitializeComponent()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>#endregion<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /> </p><h2>Código en program.cs<br /></h2><p>Reemplace el código del modulo program.cs por el código que figura a continuación<br /></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Windows.Forms;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Globalization;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Net.Sockets;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">namespace</span> UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">static</span><br /><span style="color:blue;">class</span><br /><span style="color:teal;">Program<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// -<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:teal;">IPEndPoint</span> endPoint;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">//Indica si esta actuando en modo servidor o cliente<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">bool</span> client;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Entrada al programa<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">public</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">void</span> Main(<span style="color:teal;">String</span>[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// -<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (ParseArgs(args))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">//<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">Talker</span> talker = <span style="color:blue;">new</span><br /><span style="color:teal;">Talker</span>(endPoint, client);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Referencia del Talker dentro del Form<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">TalkForm</span> form = <span style="color:blue;">new</span><br /><span style="color:teal;">TalkForm</span>(talker);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Arranca el talker<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>talker.Start();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Arranca la apliacion con el Form<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">Application</span>.Run(form);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Parser de la linea de comandos<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">bool</span> ParseArgs(<span style="color:teal;">String</span>[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">try<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">IPAddress</span>.Any, 5150);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args[0][0] != <span style="color:maroon;">'/'</span> && args[0][0] != <span style="color:maroon;">'-'</span>)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">switch</span> (<span style="color:teal;">Char</span>.ToUpper(args[0][1], <span style="color:teal;">CultureInfo</span>.InvariantCulture))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">case</span><br /><span style="color:maroon;">'L'</span>: <span style="color:green;">//Listen: Escucha<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">int</span> port = 5150;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length > 1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = <span style="color:teal;">Convert</span>.ToInt32(args[1]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">IPAddress</span>.Any, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">break</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">case</span><br /><span style="color:maroon;">'C'</span>:<span style="color:green;">//Call: Llama<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = 5150;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">String</span> address = <span style="color:maroon;">"127.0.0.1"</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length > 1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>address = args[1];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = <span style="color:teal;">Convert</span>.ToInt32(args[2]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">Dns</span>.GetHostEntry(address).AddressList[0], port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">break</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">default</span>:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">catch<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Como se usa<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static void ComoUsarme()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">MessageBox.Show</span>("UnChat [switch] [parametros...]\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>" /L [port]\t\t-- Escucha en el port. Default: 5150\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>" /C [direccion] [port]\t-- Conecta a una direccion y port.\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Ejemplo Server - \n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"UnChat /L\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Ejemplo Client - \n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"UnChat /C NombreDeServidor 5150", "Uso de UnChat");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><h2>Código en Talker.cs<br /></h2><p><br /> </p><p>Creemos ahora la clase que representara al Talker<br /></p><p><br /> </p><p><br /> </p><p>Y coloquemos dentro del archivo de esta clase el código que se indica a continuación:<br /></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net.Sockets;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.IO;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Threading;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>namespace UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Esta clase es una capa que encpasula a la clase Socket y le agrega<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// algunas habilidades de chateo.-<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>class Talker : IDisposable<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private Socket socket;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private TextReader reader;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private TextWriter writer;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bool client;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint endPoint;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String prevSendText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String prevReceiveText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String statusText;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private Status status;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Constructor<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public Talker(IPEndPoint endPoint, bool client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.endPoint = endPoint;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.client = client;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = null;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>statusText = prevSendText = prevReceiveText = String.Empty;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// -<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>~Talker()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Dispose();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Este es un modo ordenado y seguro de liberar todos<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//los recursos que se usaron en el momento en que se baja<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//la aplicacion<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void Dispose()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>GC.SuppressFinalize(this);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (reader != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (writer != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (socket != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Clase delegate y evento<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public delegate<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void NotificationCallback(Notification notify, Object data);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public event NotificationCallback Notifications;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// enum de los tipos de notificaciones<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public enum Notification<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Initialized = 1,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>StatusChange,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceivedRefresh,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceivedAppend,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>End,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Error<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// enum de los posibles estados<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public enum Status<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Escuchando,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Conectado,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Cliente<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// EL inicio de una instancia de la clase es un thread<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//que se encola en el pool de threads<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void Start()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ThreadPool.QueueUserWorkItem(new WaitCallback(EstablishSocket));<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Envio de texto a la coneccion remota<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void EnviaMensaje(String newText)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String send;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// es un agregado al texto (append)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if ((prevSendText.Length <= newText.Length) && String.CompareOrdinal(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>newText, 0, prevSendText, 0, prevSendText.Length) == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String append = newText.Substring(prevSendText.Length);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>send = String.Format("A{0}:{1}", append.Length, append);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}// o reemplazo completo<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>send = String.Format("R{0}:{1}", newText.Length, newText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Envio datos y hace flush<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Write(send);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Flush();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Guardar el texto para comparar si es necesario<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevSendText = newText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Notifica un estado<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void SetStatus(Status status)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.status = status;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.StatusChange, status);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Establecer una coneccion via socket y comenzar la recepcion<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void EstablishSocket(Object state)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>NetworkStream stream = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Si no es un cliente, entonces levantar una Escucha (listener)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (!client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket listener;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener = new Socket(AddressFamily.InterNetwork,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Blocking = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Bind(endPoint);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Escuchando);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Listen(0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = listener.Accept();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stream = new NetworkStream(socket);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = new StreamReader(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = new StreamWriter(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Write("WINTALK .NET");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Flush();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (SocketException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Este error indica que alguien esta usando el puerto<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//Asumamos que en ese caso se debe intentar conectarse como un cliente<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//pensando que ya hay un server para los nodos de la red<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (e.ErrorCode == 10048)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = new IPEndPoint(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Dns.Resolve("127.0.0.1").AddressList[0], endPoint.Port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notification.Error,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Error al inicializar el Socket:\n" + e.ToString());<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Intenta coneccion como cliente<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Cliente);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket temp = new<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket(AddressFamily.InterNetwork,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>temp.Blocking = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>temp.Connect(endPoint);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = temp;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stream = new NetworkStream(socket);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = new StreamReader(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = new StreamWriter(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] handshake = new char[12];<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader.Read(handshake, 0, 12);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string sHandShake = new string(handshake);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (!(reader.Read(handshake, 0, 12) > 0 && sHandShake == "WINTALK .NET"))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Si establecimos el socket, comenzar a chatear<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (socket != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Conectado);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Initialized, this);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// -<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//NetworkStream.Read()es un metodo llamado por el metodo ReceiveTalk<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//El primer metodo genera una excepcion cuando se cierra la coneccion remota<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//La excepcion se maneja en el catch<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceiveTalk();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Por aca pasa cuando NetworkStream.Read() retorna un cero (algo que hace<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//en alguans versiones del SO<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.End, "La coneccion remota se cerro.");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Falla al establecer el , Verifique si especifico el port correcto");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (IOException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketException sockExcept = e.InnerException as SocketException;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (sockExcept != null && 10054 == sockExcept.ErrorCode)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.End, "La coneccion remota se cerro.");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (Notifications != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error, "Error :\n" + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (Exception e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error, "Error:\n" + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Recibe la comunicacion del cliente remoto<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void ReceiveTalk()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] commandBuffer = new char[20];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] oneBuffer = new char[1];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int readMode = 1;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int counter = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>StringBuilder text = new StringBuilder();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>while (readMode != 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (reader.Read(oneBuffer, 0, 1) == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>switch (readMode)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 1:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (counter == commandBuffer.Length)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (oneBuffer[0] != ':')<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>commandBuffer[counter++] = oneBuffer[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>counter = Convert.ToInt32(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>new String(commandBuffer, 1, counter - 1));<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (counter > 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 2;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>text.Length = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else if (commandBuffer[0] == 'R')<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>counter = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText = String.Empty;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedRefresh, prevReceiveText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 2:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>text.Append(oneBuffer[0]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (--counter == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>switch (commandBuffer[0])<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 'R':<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText = text.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedRefresh, prevReceiveText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>default:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string newText = text.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText += newText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedAppend, newText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 1;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>default:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><h2>Como ejecutar la aplicación<br /></h2><p><br /> </p><p>Usar una sesión como cliente y otra como servidor<br /></p><p>Para eso generar dos archivos .bat (llamémoslos ChatCliente.bat y ChatServer.bat) que inicien cada uno una sesión del programa<br /></p><p><br /> </p><p>Por ejemplo para <strong>ChatCliente.bat</strong><br /></p><p>UnChat.exe /C m3nb02 5150<br /></p><p>Que significa que el programa desea actuar como Cliente (de allí la letra C) del equipo <strong>m3nb02</strong> (es el nombre de mi equipo en esta red en la que estoy trabajando) y "hablar" por el port 5150.-<br /></p><p><br /> </p><p>Por ejemplo para <strong>ChatServer.bat</strong><br /></p><p><br /> </p><p>UnChat.exe /L 5150<br /></p><p>Que significa que el programa desea actuar como Server (La letra L por Listen) y "hablar" por el port 5150.-<br /></p><p><br /> </p><h2>Sockets y Ports<br /></h2><h2>El protocolo FTP<br /></h2><p>Codigos de retorno de FTP<br /></p><div><table style="BORDER-COLLAPSE: collapse" border="0"><colgroup><col style="WIDTH: 42px"><col style="WIDTH: 554px"></colgroup><tbody valign="top"><tr style="BACKGROUND: #f2f2f2"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: #aaaaaa 0.75pt solid; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;"><strong>Code</strong></span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: #aaaaaa 0.75pt solid; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p style="TEXT-ALIGN: center"><span style="font-family:Times New Roman;font-size:12;"><strong>Explanation</strong></span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">100</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Series: The requested action is being initiated, expect another reply before proceeding with a new command.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">110</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Restart marker replay . In this case, the text is exact and not left to the particular implementation; it must read: MARK yyyy = mmmm where yyyy is User-process data stream marker, and mmmm server's equivalent marker (note the spaces between markers and "=").</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">120</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service ready in nnn minutes.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">125</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Data connection already open; transfer starting.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">150</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">File status okay; about to open data connection.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">200</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command okay.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">202</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented, superfluous at this site.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">211</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">System status, or system help reply.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">212</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Directory status.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">213</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">File status.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">214</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Help message.On how to use the server or the meaning of a particular non-standard command. This reply is useful only to the human user.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">215</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">NAME system type. Where NAME is an official system name from the list in the Assigned Numbers document.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">220</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service ready for new user.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">221</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service closing control connection.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">225</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Data connection open; no transfer in progress.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">226</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Closing data connection. Requested file action successful (for example, file transfer or file abort).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">227</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Passive Mode (h1,h2,h3,h4,p1,p2).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">228</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Long Passive Mode (long address, port).</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">229</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Extended Passive Mode (port).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">230</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User logged in, proceed. Logged out if appropriate.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">231</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User logged out; service terminated.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">232</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Logout command noted, will complete when transfer done.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">250</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action okay, completed.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">257</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">"PATHNAME" created.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">331</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User name okay, need password.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">332</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Need account for login.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">350</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action pending further information</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">421</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service not available, closing control connection. This may be a reply to any command if the service knows it must shut down.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">425</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Can't open data connection.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">426</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Connection closed; transfer aborted.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">434</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested host unavailable.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">450</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action not taken.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">451</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action aborted. Local error in processing.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">452</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. Insufficient storage space in system.File unavailable (e.g., file busy).</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">500</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Syntax error, command unrecognized. This may include errors such as command line too long.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">501</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Syntax error in parameters or arguments.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">502</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">503</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Bad sequence of commands.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">504</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented for that parameter.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">530</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Not logged in.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">532</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Need account for storing files.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">550</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. File unavailable (e.g., file not found, no access).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">551</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action aborted. Page type unknown.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">552</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action aborted. Exceeded storage allocation (for current directory or dataset).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">553</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. File name not allowed.</span> </p></td></tr></tbody></table></div><p><br /> </p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-32525617214118889252011-01-23T13:12:00.001-08:002011-03-24T02:53:39.960-07:00<span xmlns=""><p><br /></p><p><br /></p><p><br /></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Manual del<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Lenguaje de programación<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>C#<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Parte V-A<br /></strong></span></p><p style="TEXT-ALIGN: center"><br /></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Programación con hilos múltiples (Threads) y uso de Patrones de Diseño<br /></strong></span></p><p><br /></p><p><br /></p><p></p><p style="MARGIN-LEFT: 18pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628652"><span style="font-family:Verdana;font-size:10;">OBJETIVO DEL MANUAL 3</span><span style="font-family:Times New Roman;font-size:12;"><br /></span></a></p><p style="MARGIN-LEFT: 18pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628653"><span style="font-family:Verdana;font-size:10;">Un motor de procesos batch 3</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628654"><span style="font-family:Verdana;font-size:10;">La Interfaz Comando 4</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628655"><span style="font-family:Verdana;font-size:10;">Las clases que implementan la interfaz Comando 4</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628656"><span style="font-family:Verdana;font-size:10;">La clase miClase 4</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628657"><span style="font-family:Verdana;font-size:10;">La clase miOtraClase 6</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628658"><span style="font-family:Verdana;font-size:10;">El motor batch de tareas asíncronas 8</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628659"><span style="font-family:Verdana;font-size:10;">Un programa que utiliza el motor batch 10</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 18pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628660"><span style="font-family:Verdana;font-size:10;">Una mejor versión del motor de procesos batch 12</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628661"><span style="font-family:Verdana;font-size:10;">La Interfaz de Comandos 12</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628662"><span style="font-family:Verdana;font-size:10;">La clase abstracta AbstractComando 15</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=3252561721411888925#_Toc170628663"><span style="font-family:Verdana;font-size:10;">Una mejora en el motor batch de tareas asincrónicas 16</span></a><span style="font-family:Times New Roman;font-size:12;"><br /></span></p><p><br /></p><p><br /></p><p><br /></p><h1>OBJETIVO DEL MANUAL<br /></h1><p><br /></p><p>Es intención en este manual presentar un modelo de implementación de threads así como la implementación de dos patrones de desarrollo clásicos: Command y Strategy.-<br /></p><p>Para eso vamos a plantearnos un motor batch , es decir un proceso que sea capaz de disparar procesos batch (no interactivos ) en diferentes hilos de ejecucion<br /></p><p><br /></p><h1>Un motor de procesos batch<br /></h1><p>Un motor de procesos batch es un software que es capaz de ejecutar procesos batch de modo concurrente y controlado.-<br /></p><p>Lo que expondremos acá es un modelo simple del mismo del que después pueda derivarse un motor de uso profesional.-<br /></p><p>Lo importante del motor desde el punto de vista de la arquitectura es que se trata de una aplicación que es capaz de manejar múltiples hilos de ejecución, colocar en cada uno de esos hilos un proceso a ejecutar , lanzar dichos procesos , esperar su conclusión y reportar que el proceso finalizo.-<br /></p><p>Lo importante del motor desde el punto de vista de la técnica de diseño es que cumple con un patrón de los enunciados por Gamma y otros (GoF []). Este patrón se denomina Command (Comando).-<br /></p><p>La idea de Comando como patrón de nuestro diseño es un objeto que tenga 3 estadios clásicos: Inicio, ejecución y cierre. Llamaremos a esos métodos como Inicio(), run() y CleanUp().-<br /></p><p><br /></p><p><br /></p><h2>La Interfaz Comando<br /></h2><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Text;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">namespace</span> ThreadPoolTest_5<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">public</span><br /><span style="color:blue;">interface</span><br /><span style="color:teal;">Comando<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">void</span> inicio();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">void</span> run();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">void</span> cleanup();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><h2>Las clases que implementan la interfaz Comando<br /></h2><p>Veamos ahora clases concretas de la Interfaz comando. Estas clases implementan los métodos declarados en la interfaz.-<br /></p><p>Daremos dos implementaciones una llamada miClase y la otra llamada miOtraClase.-<br /></p><p>No tienen nada de particular salvo que ambas implementan a la interfaz Comando.-<br /></p><h3>La clase miClase<br /></h3><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Threading;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace ThreadPoolTest_5<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public class miClase : Comando<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private string _nombre;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private bool _terminado;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public string nombre<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _nombre; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _nombre = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public bool terminado<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _terminado; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _terminado = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void inicio()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = false;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void run()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine(this.GetType().ToString() + " :Procesando requerimiento '{0}'." +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>" Hash: {1}",<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>(string)nombre, Thread.CurrentThread.GetHashCode());<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>// Simulacion de tiempo de procesamiento<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>int ticks = Environment.TickCount;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//Trabajar mientras no hayan transcurrido los 2 segundos<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>while (Environment.TickCount - ticks < 2000) ;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("Requerimiento '{0}' procesado",<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>(string)nombre);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void cleanup()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//clase<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//namespace<br /></strong></span></p><p><br /></p><h3>La clase miOtraClase<br /></h3><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Threading;<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace ThreadPoolTest_5<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public class miOtraClase : Comando<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private string _nombre;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private bool _terminado;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public string nombre<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _nombre; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _nombre = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public bool terminado<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _terminado; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _terminado = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void inicio()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = false;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void run()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine(this.GetType().ToString() +": Procesando requerimiento '{0}'." +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>" Hash: {1}",<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>(string)nombre, Thread.CurrentThread.GetHashCode());<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//Calcular<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>CalcularCosenos();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("Requerimiento '{0}' procesado",<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>(string)nombre);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private void CalcularCosenos()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>const double EPSILON = 0.000000001;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>const double DESDE = 0.5346222;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>const double HASTA = 3.1415926;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>const double PASO = 0.000001999;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double lRadianes = DESDE;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double RadCuadrado;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double s;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double t;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double dFabsLRas;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>double dFabsProd;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>int k;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>string Aux = "";<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>while (lRadianes < HASTA)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>k = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>t = 1;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>s = 1;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>RadCuadrado = lRadianes * lRadianes;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>dFabsLRas = Math.Abs(t);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>dFabsProd = (EPSILON * Math.Abs(s));<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>while (dFabsLRas > dFabsProd)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>k = k + 2;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>t = (-1) * t * RadCuadrado / (k * (k - 1));<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>// 1 - x^2/2! ...<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>s = s + t;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>dFabsProd = (EPSILON * Math.Abs(s));<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>dFabsLRas = Math.Abs(t);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Aux = lRadianes.ToString() + ":" + s.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//Mostrar Aux<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>lRadianes += PASO;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public void cleanup()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><h2>El motor batch de tareas asíncronas<br /></h2><p>Ahora vamos a implementar el motor.-<br /></p><p>El motor de tareas asíncronas representa una implementación de un modelo de procesamiento al que también llamamos monitor.<br /></p><p>Se trata de un software capaz de disparar OTRAS tareas según una configuración de tiempos.-<br /></p><p>En el ejemplo estamos utilizando 4 conceptos sobre los que el motor esta diseñado:<br /></p><ol><li>Para que el motor deba ejecutar un proceso en hilos (threads) múltiples usaremos un namespace llamado System.Threading en el que encontramos una clase llamada WaitCallback que es la implementación de un prototipo de función CallBack.-<br /></li><li>La clase WaitCallback, necesita en su constructor un método que cumpla con este prototipo :<br /></li></ol><p><br /><span style="font-family:Courier New;"><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">void</span> MiFuncion(<span style="color:blue;">object</span> miObjeto);<br /></span></p><p>De modo que nosotros creamos un método dentro de nuestra clase de implementación del motor que pueda cumplir con este prototipo.-<br /></p><ol><li>La clase ThreadPool, con métodos estáticos públicos es la que nos permitirá levantar cada uno de los procesos que el motor batch dispara. ThreadPool nos permite definir la cantidad de threads que se abrirán en la sesión así como encolar los procesos que disparamos de modo de ejecutarlos secuencialmente.-<br /></li><li>EL motor tiene un método llamado <span style="font-family:Comic Sans MS;font-size:9;"><strong>Trabaja()</strong></span> que es el que ejecuta la parte central de la tarea. Ahora bien : ¿ Que necesita <span style="font-family:Comic Sans MS;font-size:9;"><strong>Trabaja()</strong></span> para hacer su tarea ?.<br /></li></ol><p>Necesita una lista de objetos. De alli que <span style="font-family:Comic Sans MS;font-size:9;"><strong>Trabaja()</strong></span> tiene como parámetro un contenedor genérico <span style="font-family:Comic Sans MS;font-size:9;"><strong><List></strong></span> de objetos a procesar.-<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Threading;<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace ThreadPoolTest_5<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>class MotorBatch<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public static void trabaja(List<object> cm)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//EL motor tiene su funcion de disparo y arma un<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">// handler a ella<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>WaitCallback callBack;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>callBack = new WaitCallback(FuncionAEjecutar);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//El motor ajusta la cantidad de threads por procesador<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>int minWorker, minIOC;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.GetMinThreads(out minWorker, out minIOC);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>// 4 threads asincronicos como minimo, por procesador<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.SetMinThreads(4, minIOC);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//El motor lanza las tareas<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>foreach(object com in cm)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.QueueUserWorkItem(callBack, com);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//El motor sincroniza el pool de threads<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//Hasta terminar<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.ReadLine();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private static void FuncionAEjecutar(object mc)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Comando xco = (Comando)mc;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.inicio();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.run();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.cleanup();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//clase<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//namespace<br /></strong></span></p><p><br /></p><h2>Un programa que utiliza el motor batch<br /></h2><p>Corresponde ahora que hagamos un programa que utiliza el motor batch para dispara procesos. Lo que haremos será que el motor dispare las implementaciones de Comando que hicimos con miClase y miOtraClase.-<br /></p><p>Observemos que es lo que nuestro programa hace ahora:<br /></p><p>Siendo que el motor necesita que a su método publico y estático Trabaja() se le pase como parámetro un genérico de tipo <List> con objetos, lo primero que hace la aplicación que llamara al motor es generar una lista de dicho tipo.<br /></p><p>Podemos ir viendo ya que esta generación es una tarea que debería estar controlada en el sentido que no podemos colocar cualquier tipo de objetos en esa lista sino solamente aquellos que deriven de Comando. Ese punto lo revisaremos en las mejoras que haremos al motor batch.-<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Threading;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace ThreadPoolTest_5<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>class MainApp<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>static void Main()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//Alguien carga los comandos en una lista y el motor<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//la invoca<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>List<object> cm = ListaDeComandos();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>MotorBatch.trabaja(cm);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>static public List<object> ListaDeComandos()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>miClase mc;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>miOtraClase moc;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>List<object> comandos = new List<object>();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>for (int i = 0; i < 10; i++)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>if ((i % 2) != 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>mc = new miClase();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>mc.nombre = "Hilo nro: " + i;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>comandos.Add(mc);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>moc = new miOtraClase();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>moc.nombre = "Hilo nro: " + i;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>comandos.Add(moc);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return comandos;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><h1>Una mejor versión del motor de procesos batch<br /></h1><h2>La Interfaz de Comandos<br /></h2><p>Si hacemos un análisis más meticuloso de la estructura que tendrá el motor batch, vemos que el diseño no solamente se adecua al uso de una interfaz (que es la representación de una plantilla con métodos comunes para polimorfismo) sino que podemos tener una clase abstracta con implementaciones de dichos métodos comunes.-<br /></p><p>Estas implementaciones en algunos de los casos serán luego sobrescritas por las implementaciones de la clase abstracta y en otros casos serán implementados ya que algunos métodos los declararemos también como abstractos.-<br /></p><p><br /></p><p><br /></p><p>Usando la utilidad View Class Diagram de Visual Studio, podemos ver las relaciones entre la Interfaz (y su declaración de métodos) con la clase abstracta y una clase (miClase) que implementa a esta ultima.-<br /></p><p>Esta relación entre Interfaz-Clase Abstracta-Clase Concreta es un ejemplo de cómo debemos diseñar este tipo de problemas de ingeniería:<br /></p><ol><li>Un problema requiere de la confección de un algoritmo que ejecuta acciones de objetos que tienen métodos comunes, pero se instancian de CLASES DISTINTAS. En nuestro caso el problema es la ejecución de los métodos de un comando.-<br /></li><li>Esto nos lleva a la idea de polimorfismo. Para eso entonces diseñamos la interfaz y pensamos los métodos comunes.-<br /></li><li>Existen además métodos que admiten cierta implementación o directamente necesitan de ella. Otros métodos, en cambio, deben ser definido para cada clase concreta<br /></li><li>Esto nos lleva a la idea de clase abstracta y métodos virtuales. La clase será la base de otras que heredaran su comportamiento pero lo especializaran.-<br /></li></ol><p><br /></p><p><br /></p><ol><li>El diseño de una clase abstracta es una tarea de pasos sucesivos. No es el primer eslabón de la cadena sino algún punto de culminación ya que implica que hemos visualizado un patrón de comportamiento del sistema y que hay tareas que sabemos que son comunes.-<br /></li><li><div>Si hemos llegado a ese punto del diseño, podremos diferenciar entre aquellos métodos que serán implementados en la clase abstracta y posiblemente ampliados en la subclase, y aquellos otros métodos a los que NECESARIAMNETE implementara la subclase.<br /></div><p>En nuestro caso, <span style="font-family:Comic Sans MS;font-size:9;"><strong>Inicio()</strong></span> y <span style="font-family:Comic Sans MS;font-size:9;"><strong>YaTermino()</strong></span> por ejemplo, han sido implementadas en la interfaz, en tanto presentan una lógica que entendemos común a todos los derivados.<br /></p></li></ol><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public virtual void inicio()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = false;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public bool YaTermino()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return (_terminado == true);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p style="MARGIN-LEFT: 36pt">EN cambio <span style="font-family:Comic Sans MS;font-size:9;"><strong>run()</strong></span> que es el proceso de ejecución en si de la clase, será necesariamente implementado por la subclase. De allí que coloquemos a este ultimo método como abstract.<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public abstract void run();<br /></strong></span></p><p><br /></p><h2>La clase abstracta AbstractComando<br /></h2><p>Dentro del archivo donde declaramos la Interfaz Comando, colocaremos una clase Abstracta que contenga los métodos básicos y una implementación mínima de los mismos.-<br /></p><p>Llamamos a esta clase AbstractComando<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Text;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace threadPoolTest_6<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public interface Comando<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>void inicio();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>void run();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>void cleanup();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>bool YaTermino();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>String elNombre();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public abstract class AbstactComando:Comando<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public static string CLASE_BASE = "threadPoolTest_6.AbstactComando";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private string _nombre;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private bool _terminado;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public string nombre<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _nombre; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _nombre = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public String elNombre()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return _nombre;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public virtual void inicio()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = false;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public bool YaTermino()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return (_terminado == true);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public abstract void run();<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public virtual void cleanup()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_terminado = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><h2>Una mejora en el motor batch de tareas asincrónicas<br /></h2><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Collections;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Threading;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>using System.Reflection;<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace threadPoolTest_6<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public class MotorBatch<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public static void trabaja(List<object> cm)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//EL motor tiene su funcion de disparo y arma un<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">// handler a ella<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>WaitCallback callBack;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>callBack = new WaitCallback(FuncionAEjecutar);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//El motor ajusta la cantidad de threads por procesador<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>int minWorker, minIOC;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.GetMinThreads(out minWorker, out minIOC);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>// 4 threads asincronicos como minimo, por procesador<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.SetMinThreads(4, minIOC);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//El motor lanza las tareas<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>foreach(object com in cm)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>ThreadPool.QueueUserWorkItem(callBack, com);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>//El motor sincroniza la finalizacion el pool de threads<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>do<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>foreach (object com in cm)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Comando xco = (Comando)com;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>if (xco.YaTermino())<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//TODO: Logger<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("-> Comando '{0}' procesado. Restan '{1}'", xco.elNombre(), cm.Count);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>cm.Remove(xco);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>} while (cm.Count > 0);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//Hasta terminar<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//TODO:Logger<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("Motor Batch Termino");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//Esta es la funcion a la que se apunta en el callback<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//llama a los 3 metodos de un comando<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private static void FuncionAEjecutar(object mc)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Comando xco = (Comando)mc;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.inicio();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.run();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>xco.cleanup();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//clase<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public class unPar<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>String _nombreClase;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>String _nombreYPasoAssembly;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public String nombreYPasoAssembly<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _nombreYPasoAssembly; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _nombreYPasoAssembly = value;}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public String nombreClase<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>get { return _nombreClase; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>set { _nombreClase = value; }<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//-<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public unPar(String nombreClase, String nombreYPasoAssembly)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_nombreClase = nombreClase;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>_nombreYPasoAssembly = nombreYPasoAssembly;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//-<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//clase<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public class ParAssemblyClase<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>static List <unPar> lPar = null;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public static void Agregar(String nombreClase,String nombreYPasoAssembly)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>if (lPar == null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>lPar = new List<unPar>();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>unPar p = new unPar(nombreClase,nombreYPasoAssembly);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>lPar.Add(p);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>public static List<unPar> TraerLista()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return lPar;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//Retornar una lista de comandos a partir de una lista<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">// de pares Assembly-clase que se busca cargado en la misma sesion<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>static public List<object> ListaComandos()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>List<object> comandos = null;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>if (lPar != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>comandos= ListaComandos(lPar);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return comandos;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//Retornar una lista de comandos a partir de una lista<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">// de pares Assembly-clase que se recibe<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>static public List<object> ListaComandos(List<unPar> tabla)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Assembly assem;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Object o;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>List<object> comandos = new List<object>();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>IEnumerator i = tabla.GetEnumerator();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>unPar m;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>while (i.MoveNext())<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>m = (unPar)i.Current;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>assem = Assembly.LoadFrom(m.nombreYPasoAssembly);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//Los constructores de las clases que implementan<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//Comando no tienen parametros. De alli el parametro<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//new Object[] { }<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>o = assem.CreateInstance(m.nombreClase, false,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>BindingFlags.ExactBinding, null, new Object[] { }, null, null);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//TODO: Logger<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("Clase Base de {0} : {1}",m.nombreClase, o.GetType().BaseType.ToString());<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong>//solo los que extienden AbstractComando son considerados<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;">//procesos a aejecutar<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>if (o.GetType().BaseType.ToString().Equals( AbstactComando.CLASE_BASE))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>comandos.Add(o);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>catch (Exception ex)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{ </strong>//TODO: Logger<strong><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>Console.WriteLine("Excepcion " + ex.StackTrace);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>return comandos;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//-<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//clase<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}//namespace<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong><br /></strong></span></p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-45802005320570885382011-01-23T13:05:00.001-08:002011-01-23T13:19:31.745-08:00Mas sobre reflection<span xmlns=""><p style="TEXT-ALIGN: center"><br /> </p><p style="TEXT-ALIGN: center"><br /> </p><p style="TEXT-ALIGN: center"><br /> </p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Manual del<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Lenguaje de programación<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>C#<br /></strong></span></p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Parte III<br /></strong></span></p><p style="TEXT-ALIGN: center"><br /> </p><p style="TEXT-ALIGN: center"><span style="font-family:Arial;font-size:26;"><strong>Reflection<br /></strong></span></p><p style="TEXT-ALIGN: center"><br /> </p><p><br /> </p><p><br /> </p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445761"><span style="font-family:Verdana;font-size:10;">OBJETIVO DEL MANUAL 3</span><br /></a></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445762"><span style="font-family:Verdana;font-size:10;">OBJETIVO DEL MANUAL 3</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445763"><span style="font-family:Verdana;font-size:10;">Reflection 3</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445764"><span style="font-family:Verdana;font-size:10;">¿Como funciona esto y para que sirve realmente? 3</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445765"><span style="font-family:Verdana;font-size:10;">El enfoque en C# 7</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445766"><span style="font-family:Verdana;font-size:10;">Ejemplo I: 7</span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445767"><span style="font-family:Verdana;font-size:10;">¿Como acceder a una clase del assembly? 7</span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445768"><span style="font-family:Verdana;font-size:10;">¿Como acceder a un metodo de la clase? 8</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445769"><span style="font-family:Verdana;font-size:10;">Algo más al respecto 12</span></a><br /></p><p><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445770"><span style="font-family:Verdana;font-size:10;">EJEMPLO II 13</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445771"><span style="font-family:Verdana;font-size:10;">El proyecto biblioteca1 14</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445772"><span style="font-family:Verdana;font-size:10;">El proyecto PruebaBiblioteca 16</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445773"><span style="font-family:Verdana;font-size:10;">¿ Como enlazar una biblioteca al proyecto ? 18</span></a><br /></p><p style="MARGIN-LEFT: 10pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445774"><span style="font-size:10;"><span style="font-family:Trebuchet MS;">El proyecto UsoDeReflection</span><span style="font-family:Verdana;"> 21</span></span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445775"><span style="font-family:Verdana;font-size:10;">¿Como acceder a los modulos de un assembly? 22</span></a><br /></p><p style="MARGIN-LEFT: 20pt"><a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_Toc276445776"><span style="font-family:Verdana;font-size:10;">Accediendo a los metodos 24</span></a><br /></p><p><br /> </p><p><br /> </p><p><h1>OBJETIVO DEL MANUAL<br /></h1><p></p><h1>Reflection<br /></h1><p><br /> </p><p><span style="font-family:Trebuchet MS;">Para la ejecucion de una aplicación .NET debemos tener presente el concepto de CONTENEDORES. Este es un concepto que se ha popularizado los ultimos años a traves de Java y difiere de los habituales run-times en que no es un agregado que lleva el ejecutable o un conjunto de bibliotecas que resuelven aspectos especificos (como graficos), SINO QUE ES UNA MAQUINA VIRTUAL dentro de la cual corre la aplicación.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Es decir esta cascara es la que separa a la aplicación del Sistema operativo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Sus ventajas en el mundo Java son obvias en tanto estos contenedores aislan al programador de especificidades de tal o cual sistema operativo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">No nos resultan tan obvias en el mundo Microsoft donde existe UN SOLO sistema operativo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Sin embargo hay otras decisiones que seguramente habrán pesado en la decisión de Microsoft de hacer un esquema de contenedores.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El primero es que este esquema permite que exista un nivel de compilación que no es la</span><br /><span style="font-family:Trebuchet MS;">generación del ejecutable mismo, sino de un lenguaje intermedio (MSIL para Microsoft, Bytecodes para Java y… P-CODE para quienes tuvimos oportunidad de trabajar profesionalmente con el maravilloso Pascal ¡!).-<br /></span></p><p><span style="font-family:Trebuchet MS;">El segundo es que varios lenguajes (al menos Visual Basic, C# y C++ en modo manejado) pueden trabajar sobre esta maquina virtual y compartir aquellos servicios, bibliotecas y assemblies que la maquina virtual necesita. Esto es un enorme avance desde el punto de vista de cómo cada lenguaje expone funcionalidades comunes a los programadores.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Tambien aca podemos decir que esto existía, para determinados servicios, en los sistemas operativos propietarios de Digital e IBM.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Sobre todo en los del primero, su sistema operativo VMS (hoy propiedad de Hewlett Packard) presentaba para la familia de lenguajes (Fortran, C, Cobol y Basic) idénticos nombres de rutinas para todo el sistema de I/O y de archivos ISAM.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Solo que en estos casos un runtime que se adjuntaba al programa compilado era el encargado de proveer esta funcionalidad comun. Esto por supuesto duplicaba el codigo en cierto punto, aunque los servicios que utilizaba el runtime estaban en el kernel del SO por lo que no era tan problemático.-<br /></span></p><h1>¿Como funciona esto y para que sirve realmente?<br /></h1><p><span style="font-family:Trebuchet MS;">Vamos a hacer un par de aplicaciones que nos muestren como funciona esto.<br /></span></p><p><span style="font-family:Trebuchet MS;">Antes de avanzar nos gustaría que repasemos como, en un lenguaje como el C, resolvemos un problema común:<br /></span></p><p><span style="font-family:Trebuchet MS;">Queremos invocar un método, que esta en una biblioteca CUYO ENLACE no se produce cuando compilamos, sino en tiempo de ejecución.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Esto da a nuestros programas otra versatilidad. Es decir nuestro programa es capaz de:<br /></span></p><p><span style="font-family:Trebuchet MS;">Cargar una biblioteca a traves de su nombre LITERAL. Es decir un string en tiempo de ejecucion (por ejemplo leido de un archivo de configuración) dira cual es la biblioteca a a cargar)<br /></span></p><p><span style="font-family:Trebuchet MS;">Colocar un apuntador a una funcion de dicha biblioteca (definible tambien como un string)<br /></span></p><p><span style="font-family:Trebuchet MS;">Hay alguna habilidad que debe tener el SO en el que trabajamos y es la de aceptar bibliotecas compartidas. En Windows estas tienen la extension .DLL y en UNIX la extension .SO<br /></span></p><p><span style="font-family:Trebuchet MS;">Es decir la biblioteca que invocaremos desde nuestra aplicación sera del tipo compartida (Shared) y no del tipo estatica (STATIC).-<br /></span></p><p><span style="font-family:Trebuchet MS;">El ejemplo lo haremos para UNIX solo para ver alguna pequeña diferencia de cómo lo hariamos en Windows.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El programa que haremos sabrá cargar una biblioteca por nombre. En nuestro caso los nombres son <span style="color:red;"><strong>lib1.so</strong></span> y <span style="color:red;"><strong>lib2.so</strong></span>. Estos nombres son totalmente arbitrarios y podrían ser cualquier otro valido para el Sistema operativo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El programa cargara alguna de estas 2 bibliotecas y llamara la función saludo().<br /></span></p><p><span style="font-family:Trebuchet MS;">Esta función existe en ambas bibliotecas y el programa es capaz de trabajar con esta redefinicion (override) ya que dependera de la biblioteca que cargue lo que determinara cual es la tarea que termine realizando.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Este es el codigo de una biblioteca escrito en ANSI C:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdio>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <dlfcn.h>; /* bibliotecas de manejo dinamico de funciones:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>dlopen(), dlclose(), dlsym() ... */<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* Explicamos como usar el programa. */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void usage(int argc, char* argv[])<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>fprintf(stderr, "Usar asi: %s [12] a los efectos de llamar a la lib1 o a la lib2 \n", argv[0]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int main(int argc, char* argv[])<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int lib_num; /* Que biblioteca usar ? */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char biblioteca[100]; /* nombre del archivo de la biblioteca */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void* lib_handle; /* manejador para la biblioteca compartida cargada*/<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void (*fn_de_la_biblioteca)(); /* puntero a UNA FUNCION de la biblioteca*/<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>const char* error; /* por si hay errores... */<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* necesito un argumento */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (argc != 2)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> usage(argc, argv); /* Chau!! */<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* Esta es la biblioteca a cargar. */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>lib_num = atoi(argv[1]); /* */<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (lib_num < 1 lib_num > 2)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> usage(argc, argv); /* Chau !! */<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>/* ahora armo el nombre de la biblioteca concatenando la palabra "lib" con el numero 1 o 2<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"> para obtener lib1.so o lib2.so */<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>sprintf(biblioteca, "lib%d.so", lib_num);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>/* carga la biblioteca que desea (lib1.so o lib2.so) */<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>lib_handle = dlopen(biblioteca, RTLD_LAZY);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (!lib_handle) {<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> fprintf(stderr, "Error: %s\n", dlerror());<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> exit(1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* cargar la funcion saludo QUE ESTA EN CUALQUIERA DE LAS DOS BIBLIOTECAS !*/<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>fn_de_la_biblioteca = dlsym(lib_handle, "saludo");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>error = dlerror();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (error) {<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> fprintf(stderr, "Error: %s\n", error);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong> exit(1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* Llamar a la funcion. */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>(*fn_de_la_biblioteca)();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* liberar el recurso */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>dlclose(lib_handle);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p>Este modulo es LIB1.SO:<br /></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdio>;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* Esta es la funcion de la biblioteca*/<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void saludo()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("Que puedo decir que no sea HOLA MUNDO?\n");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* cleanup de la biblioteca */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void _fini()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("Limpiando la biblioteca 'lib2.so'\n");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p>Este modulo es LIB2.SO:<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdio.h>;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* funcion de inicializacion: OBLIGATORIO llamarla '_init'. */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void _init()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("Inicializando biblioteca 'lib1.so'\n");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>/* Esta es lo funcion que nos importa */<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void saludo()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("HALOAA !!\n");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Como vemos este problema responde a un patrón común: La resolución en tiempo de ejecución de una funcionalidad determinada.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Los lenguajes modernos como C# y Java resuelven esto con el paradigma denominado programación reflexiva.<br /></span></p><p><span style="font-family:Trebuchet MS;">Como en muchos otros conceptos de estos lenguajes modernos, las ideas se generaron en Smalltalk y C++.-<br /></span></p><p><br /> </p><h2>El enfoque en C#<br /></h2><p><span style="font-family:Trebuchet MS;">El cargador del lenguaje común administra lo que se denominan DOMINIO de APLICACIONES.<br /></span></p><p><span style="font-family:Trebuchet MS;">El lenguaje común es el CONTENEDOR que aísla al programa del SO. Cualquier aplicación desarrollada en .NET no se comunicara directamente con APIs de WIN32, tal como lo hacíamos anteriormente sino a través de funciones, servicios, etc. del contenedor.-<br /></span></p><p><span style="font-family:Trebuchet MS;">EL DOMINIO de la APLICACIÓN es el contorno o los limites en los que trabajan aquellos objetos que pertenecen al mismo alcance de aplicación.-<br /></span></p><p><span style="font-family:Trebuchet MS;">La administración de este cargador incluye la carga de cada assembly en el dominio de aplicación adecuado y controla la disposición y arreglo en memoria del tipo de jerarquía en cada assembly.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Veamos unos ejemplos.-<br /></span></p><h1>Ejemplo I:<br /></h1><p><span style="font-family:Trebuchet MS;">En este caso haremos un proyecto que contendrá las clases que queremos acceder a través de Reflection.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Es por eso que utilizamos el método estático:<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><span style="color:teal;">Assembly</span>.GetExecutingAssembly();<br /></span></p><p><span style="font-family:Trebuchet MS;">para poder tener un objeto de la clase Assembly.<br /></span></p><p><span style="font-family:Trebuchet MS;">Este es el modo de hacerlo cuando lo que necesitamos es un objeto de una clase que está dentro del código actualmente en ejecución.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Obtenemos un objeto de la clase Assembly de este modo: <span style="font-size:9;"><strong>Assembly assem = new Assembly()</strong></span>)<br /></span></p><p><span style="font-family:Trebuchet MS;">Este el objeto creado nos permitirá, por ejemplo, instanciar objetos de las clases contenidas en el assembly.-<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Para eso el primer paso es:<br /></span></p><h3>¿Como acceder a una clase del assembly?<br /></h3><p><br /> </p><p><span style="font-family:Trebuchet MS;">El objeto de la clase Assembly tiene un método llamado </span><span style="font-family:Comic Sans MS;font-size:8;"><strong>CreateInstance().</strong></span><span style="font-family:Trebuchet MS;"> Este método admite como parámetro el nombre de una clase así como los parámetros que necesitase su constructor.<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Este método es uno de los métodos capitales de la programación reflexiva ya que nos permite a través de un texto que representa el nombre de la clase, obtener un objeto que es una instancia de la misma.-<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">El código siguiente muestra la utilización del método </span><span style="font-family:Comic Sans MS;font-size:8;"><strong>CreateInstance()</strong></span><span style="font-family:Trebuchet MS;">:<br /></span></p><p><br /> </p><p><span style="font-family:Courier New;color:green;">// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene<br /></span></p><p><span style="font-family:Courier New;color:green;">// El constructor de Ejemplo2 necesita un parametro que es un entero<br /></span></p><p><span style="font-family:Courier New;color:green;">//<br /></span></p><p><span style="font-family:Courier New;"><br /></span><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object o = assem.CreateInstance("Ejemplo2", false,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>BindingFlags.ExactBinding,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>null, new Object[] { 2 }, null, null);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Observe que se accede a una clase y se instancia un objeto de la misma a través de un parámetro que es un texto (</span><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Ejemplo2"</strong></span><span style="font-family:Trebuchet MS;">).-<br /></span></p><p><span style="font-family:Trebuchet MS;">Observe también que uno de los parámetros de </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>CreateInstance()</strong></span><span style="font-family:Trebuchet MS;"> es un array de Object al que se le envían los parámetros QUE EL CONSTRUCTOR de la clase necesita.<br /></span></p><p><span style="font-family:Trebuchet MS;">Esto es: No es suficiente con conocer el nombre de clase en el assembly sino que es preciso conocer algo más de ella.<br /></span></p><p><span style="font-family:Trebuchet MS;">Esto es similar a lo que nos sucede en el programa C que vimos al inicio en el que debemos conocer algo del PROTOTIPO de la función para hacer una llamada exitosa.-</span><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong></span></p><h3>¿Cómo acceder a un método de la clase?<br /></h3><p><span style="font-family:Trebuchet MS;">Ahora bien, tenemos un objeto O que es una instancia de una clase del assembly.<br /></span></p><p><span style="font-family:Trebuchet MS;">¿Cómo hacemos ahora para acceder a un método de dicha clase?<br /></span></p><p><span style="font-family:Trebuchet MS;">El handler al assembly (assem) tiene un método llamado GetType que obtiene información sobre el tipo exacto que se produce en tiempo de ejecución para el objeto corriente.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Es decir GetType retorna un tipo (Type). La clase Type es la base de reflection para acceder a la metada del objeto.<br /></span></p><p><span style="font-family:Trebuchet MS;">Type es una interfaz que tiene distintas implementaciones. La que aquí nos interesa, tiene un método llamado </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>GetMethod()</strong></span><span style="font-family:Trebuchet MS;"> que, tomando como parámetro el nombre del método, nos trae información del mismo. Asi:<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong></span><span style="font-family:Trebuchet MS;">Obtenida la información sobre el método, se lo puede invocar a través del método </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>Invoke</strong></span><span style="font-family:Trebuchet MS;"> de </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo</strong></span><span style="font-family:Trebuchet MS;"> .<br /></span></p><p><span style="font-family:Trebuchet MS;">Igual que en el caso anterior, si bien es posible obtener acceso al método a través de un literal (en este caso el nombre del método es : </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>MetodoDeEjemplo</strong></span><span style="font-family:Trebuchet MS;"> ), el uso posterior del método requiere conocer cuáles son los parámetros adecuados.</span><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object ret = m.Invoke(o, new Object[] { 42 });<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">En este caso el entero 42 se corresponde al tipo de datos que corresponde al Método, </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>MetodoDeEjemplo</strong></span><span style="font-family:Trebuchet MS;"><br /></span></p><p><span style="font-family:Trebuchet MS;">EL retorno que produce Invoke es un Object. EL uso posterior del mismo será parte de la lógica de negocios del programa.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Arme un proyecto de consola simple y coloque el código indicado en un modulo cs (C#)<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Y pruebe este código:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Reflection;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Security.Permissions;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Configuration;<br /></strong></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>class Ejemplo2<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private int factor;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public Ejemplo2(int f)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>factor = f;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public int MetodoDeEjemplo(int x)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("\nEjemplo2.MetodoDeEjemplo({0}) ejecutado.", x);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return x * factor;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public string OtroMetodo(string a)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>StringBuilder st = new StringBuilder("A este dato le concateno: ");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("\nEjemplo2.OtroMetodo({0}) ejecutado.", a);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>st.Append(a);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return st.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public class ejecuta<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public static void Main()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Assembly assem = Assembly.GetExecutingAssembly();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Nombre completo del Assembly:");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine(assem.FullName);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>AssemblyName assemName = assem.GetName();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("\nName: {0}", assemName.Name);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Version: {0}.{1}",<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>assemName.Version.Major, assemName.Version.Minor);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("\nAssembly CodeBase:");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine(assem.CodeBase);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//El constructor de Ejemplo2 necesita un parametro que es un entero<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object o = assem.CreateInstance("Ejemplo2", false,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>BindingFlags.ExactBinding,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>null, new Object[] { 2 }, null, null);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;">// Ahora apuntamos a un metodo del objeto:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object ret = m.Invoke(o, new Object[] { 42 });<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("MetodoDeEjemplo retorno: {0}.", ret);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo m2 = assem.GetType("Ejemplo2").GetMethod("OtroMetodo");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ret = m2.Invoke(o, new Object[] { "Este Texto" });<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("OtroMetodo retorno: {0}.", ret);<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("\nPunto de entrada del Assembly:");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine(assem.EntryPoint);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">La ejecución del código nos muestra lo siguiente:<br /></span></p><p><br /> </p><p><br /> </p><h2>Algo más al respecto<br /></h2><p><br /> </p><p><a href="http://msdn2.microsoft.com/en-us/library/hk5f40ct.aspx"><span style="font-family:Trebuchet MS;">Los</span></a><span style="font-family:Trebuchet MS;"> assemblies contienen módulos, los módulos contienen tipos y los tipos contienen funciones miembro o métodos.<br /></span></p><p><span style="font-family:Trebuchet MS;">-<br /></span></p><p><span style="font-family:Trebuchet MS;">Lo que Reflection provee son objetos que encapsulan a estas unidades (assemblies, módulos y tipos) de modo de crear dinámicamente una instancia de un tipo, ligar ese tipo a un objeto existente u obtener el tipo de un objeto existente.-<br /></span></p><p><span style="font-family:Trebuchet MS;">De este modo podemos invocar los métodos del tipo y/o acceder a sus campos y propiedades. El uso típico de reflection debería seguir estas reglas:<br /></span></p><ul><li><span style="font-family:Trebuchet MS;">Usar la clase <a href="http://msdn2.microsoft.com/en-us/library/system.reflection.assembly.aspx">Assembly</a> para definir y cargar assemblies, cargar los módulos que el assembly contiene y que se encuentran en el Manifiesto, ubicar el tipo del assembly en si y crear una instancia del mismo.-<br /></span></li></ul><p><pre><code><span style="font-family:Trebuchet MS;font-size:11;"> Esto lo podemos hacer con:<br /></span></code></pre><p></p><p><br /> </p><p><pre><code><span style="font-family:Comic Sans MS;font-size:9;"><strong> Assembly a = Assembly.LoadFrom(args[0]);<br /></strong></span></code></pre><p></p><p><span style="font-family:Trebuchet MS;">O<br /></span></p><p><strong><span style="font-family:Trebuchet MS;"><br /></span><span style="font-family:Comic Sans MS;font-size:9;">Assembly a = Assembly.GetExecutingAssembly();<br /></span></strong></p><p><span style="font-family:Trebuchet MS;"><strong><br /></strong>EL primer modo es genérico y solo requiere que se indique el assembly. (El paso completo del mismo será obligatorio si no se encuentra en la GAC). El segundo método está restringido a el trabajo con clases que se encuentran en el assembly actual.-<br /></span></p><ul><li><span style="font-family:Trebuchet MS;">Usar el método </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>CreateInstance</strong></span><span style="font-family:Trebuchet MS;">() para instanciar un objeto de un tipo dado:<br /></span></li></ul><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object o = assem.CreateInstance("Ejemplo2", false,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null); <br /></strong></span></p><p><br /> </p><ul><li><span style="font-family:Trebuchet MS;">Alternativamente observemos que esto puede hacerse así:<br /></span></li></ul><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Object ret = m.Invoke(o, new Object[] { 42 });<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;"> El método </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>GetType</strong></span><span style="font-family:Trebuchet MS;"> retorna un objeto de la clase </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>MethodInfo.<br /></strong></span></p><p><span style="font-family:Trebuchet MS;">Observemos que igual que en el caso anterior, el nombre de la clase y el de su metodo, SON LITERALES lo que indica que pdrian ser cargados en tiempo de ejecucion en variables string y la llamada a </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>Assembly.GetType</strong></span><span style="font-family:Trebuchet MS;"> o a </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>Assembly.CreateInstance</strong></span><span style="font-family:Trebuchet MS;"> se podria hacer con datos dinamicos.<br /></span></p><p><span style="font-family:Trebuchet MS;">Desde ya que esta es la funcion ultima de Reflection.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Observe de todos modos que debe conocer "algo" del tipo o del metodo de modo de invocar correctamente a los constructores o pasar parametros adecuados a los metodos.-<br /></span></p><p><br /> </p><h1>EJEMPLO II<br /></h1><p><br /> </p><p><a href="http://msdn2.microsoft.com/en-us/library/hk5f40ct.aspx"><span style="font-family:Trebuchet MS;">En</span></a><span style="font-family:Trebuchet MS;"> este ejemplo haremos una variante que nos llevara a un caso más parecido al que planteamos al principio de esta y que mostramos con un ejemplo en lenguaje C.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Construiremos 3 proyectos, ambos en la misma solucion solo a los efectos de la simplicidad.<br /></span></p><p><span style="font-family:Trebuchet MS;">Uno, al que llamaremos <span style="color:red;"><strong>biblioteca1</strong></span>, correspondera al armado de una biblioteca donde estan las clases de las que crearemos objetos a los que a accederemos.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El segundo, al que llamaremos <span style="color:red;"><strong>pruebabiblioteca</strong></span>, sera una aplicacin intermedia de ayuda. Esto no es necesario para el proyecto final que es una aplicación que usando reflection hara uso de los metodos de la biblioteca. Pero es una biena idea probar la biblioteca SEPARADAMENTE antes de darle un uso generico. Es por eso que colocamos este proyecto dentro del ejemplo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El tercero, que es el que nos importa, sera la aplicación que a traves de Reflection accede a estos objetos y sus metodos en modo dinamico.-<br /></span></p><h2>El proyecto biblioteca1<br /></h2><p><span style="font-family:Trebuchet MS;">El primer proyecto sera del tipo Class Library y en el colocaremos una clase con dos metodos.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Luego esta sera nuestra biblioteca armada como Assembly.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Vamos con el primer proyecto que consiste en armar la biblioteca de la clase que expondra funcionalidad a ser utilizada por el segundo proyecto:<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Este es un proyecto Class Library de modo de armar una biblioteca con una clase que exporte sus metodos.-<br /></span></p><p><span style="font-family:Trebuchet MS;">El codigo que escribiremos para crear tal clase es el que se muestra a continuacion:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>namespace biblioteca1<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public class UnaClase<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public static Boolean SinNumeros(string dato)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char []numeros = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (dato.LastIndexOfAny(numeros) == -1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return (true);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return (false);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public static Boolean SinÑuflos(string dato)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char []ñuflos = new char[] { '@', '^', '`', '¨', '~' };<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (dato.LastIndexOfAny(ñuflos) == -1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return (true);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return (false);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Ahora vamos a armar la biblioteca (biblioteca1) como una dll que expondrá la clase </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>UnaClase</strong></span><span style="font-family:Trebuchet MS;"> y sus métodos públicos.-<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Esto generara el archivo biblioteca1.dll .-<br /></span></p><p><span style="font-family:Trebuchet MS;"><strong>Revise en la pantalla de salida donde queda generada</strong>:<br /></span></p><p><br /> </p><p><br /> </p><h2><span style="font-family:Trebuchet MS;font-size:11;"><br /></span>El proyecto PruebaBiblioteca<br /></h2><p><span style="font-family:Trebuchet MS;">Ahora vamos a construir el segundo proyecto:<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Vamos a hacer una aplicación de consola que utilice la biblioteca creada en el proyecto anterior.<br /></span></p><p><span style="font-family:Trebuchet MS;">Lo hará del modo habitual, es decir sin utilización de reflection.<br /></span></p><p><span style="font-family:Trebuchet MS;">EL código C# de este proyecto esta en un solo modulo al que llamaremos Program y es el que se ve a continuación:<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using biblioteca1;<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>namespace PruebaBiblioteca<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>class Program<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>static void Main(string[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string dato = "ABCDE";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (biblioteca1.UnaClase.SinNumeros(dato) == true)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: No tiene numeros");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: Tiene numeros");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>dato = "AB1C2DE";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (biblioteca1.UnaClase.SinNumeros(dato) == true)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: No tiene numeros");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: Tiene numeros");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>dato = "A~CDE";<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (biblioteca1.UnaClase.SinÑuflos(dato) == true)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: No tiene Ñuflos");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("{0}: Tiene Ñuflos");<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><h2>¿ Como enlazar una biblioteca al proyecto ?<br /></h2><p><span style="font-family:Trebuchet MS;">Para enlazar la biblioteca con el proyecto PruebaBiblioteca1 colóquese en la ventana "Solution Explorer" , coloque el mouse sobre el proyecto y pulsando el botón derecho elija Add Reference<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Si la bibloteca esta bien construida la salida de la ejecucion de este programa sera algo asi:<br /></span></p><p><br /> </p><h2><span style="font-family:Trebuchet MS;font-size:11;">El proyecto UsoDeReflection<br /></span></h2><p><span style="font-family:Trebuchet MS;">Armemos ahora el tercer proyecto.-<br /></span></p><p><span style="font-family:Trebuchet MS;">También será un proyecto de consola.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Siendo que en el código no haremos una mención explicita a los métodos de la biblioteca, sino que haremos un binding tardío, cuando el programa se ejecute NO NECESITAMOS referenciar la biblioteca1.<br /></span></p><p><span style="font-family:Trebuchet MS;">Si necesitaremos desde ya el paso completo de donde se encuentra.-<br /></span></p><p><span style="font-family:Trebuchet MS;">En mi caso la colocare en el disco C: dentro del directorio M3.-<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Es por eso que en el codigo hemos colocado:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>static void Main(string[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Assembly a = Assembly.LoadFrom(@"c:\m3\biblioteca1.dll");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>…..<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}//-<br /></strong></span></p><p><span style="font-family:Trebuchet MS;">Desde ya que esta mencion "hard-code" puede ser reemplazada por la lectura de un parametro en un archivo de propiedades o en un archivo de configuracion.-<br /></span></p><h3>¿Como acceder a los modulos de un assembly?<br /></h3><p><span style="font-family:Trebuchet MS;">El primer metodo que invocamos (llamado </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>VerModulosYTipos</strong></span><span style="font-family:Courier New;">) </span><span style="font-family:Trebuchet MS;">hace una recorrida sobre los modulos del assembly.-<br /></span></p><p><span style="font-family:Trebuchet MS;">En este caso solo encuentra <strong>un solo modulo</strong> ya que la biblioteca1 fue armada con un unico archivo cs dentro de un UNICO namespace:<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Sobre esto aclaremos que lo que define al modulo no es la cantidad de archivo C Sharp (archivos .cs) ya que en todo caso el archivo físico es una unidad de agrupamiento de código compilable. Pero en el momento de enlazar estos archivos compilados, existen unidades superiores al archivo físico, como:<br /></span></p><ul><li><span style="font-family:Trebuchet MS;">La clase en la que participa ese archivo (recordar que varios archivos se pueden utilizar para componer una sola clase)<br /></span></li></ul><p><br /> </p><ul><li><span style="font-family:Trebuchet MS;">El namespace al que pertenece el código que está en el archivo.<br /></span></li></ul><p><br /> </p><p><span style="font-family:Trebuchet MS;">Con esto presente podemos entender que:<br /></span></p><p><br /> </p><ol><li><span style="font-family:Trebuchet MS;">La proyecto con el que armamos la DLL es el que le da el nombre a la DLL.-<br /></span></li><li><span style="font-family:Trebuchet MS;">Podemos también armar una DLL dentro de un proyecto que se encuentra a su vez dentro de una solución.-<br /></span></li><li><span style="font-family:Trebuchet MS;">Este proyecto tendrá, en el momento del armado, un NAMESPACE por defecto. Esto significa que dentro del proyecto podemos tener varios NAMESPACES. Esto NAMESPACES permitirán agrupar clases dentro de sí. Esa es la función básica del NAMESPACE: Un agrupador de clases que a criterio del diseñador del sistema deben estar bajo un espacio común.-<br /></span></li><li><span style="font-family:Trebuchet MS;">El NAMESPACE mas el nombre de la CLASE es lo que denominados nombre calificado completo de la clase.-<br /></span></li><li><span style="font-family:Trebuchet MS;">El NAMESPACE mas el nombre de la CLASE mas el nombre del método y sus parámetros identifican de modo UNIVOCO dentro de una solución la llamada a un método de una clase.-<br /></span></li><li><span style="font-family:Trebuchet MS;">Un proceso ejecutándose es un espacio en el que existen recursos de procesador (tiempo y memoria) y en el que todas las partes participantes (métodos de clases y atributos en última instancia) deben estar unívocamente identificados.-<br /></span></li></ol><p><br /> </p><p><span style="font-family:Trebuchet MS;">Dentro de una DLL cada MODULO es cada uno de los PROYECTOS que figura dentro de la SOLUCION. (Vea el <a href="http://www.blogger.com/post-edit.g?blogID=4330427453885266705&postID=4580200532057088538#_EJEMPLO_III">Ejemplo III</a> para mas detalles sobre estos puntos) .-<br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">El trabajo de </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>VerModulosYTipos </strong></span><span style="font-family:Trebuchet MS;">es tomar los modulos del assembly en un array de </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>Module[</strong></span><span style="font-family:Trebuchet MS;">]<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Module[] m = a.GetModules();</strong></span><span style="font-family:Courier New;"><br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">y de cada modulo (en este caso uno solo) revisar los tipos que los componen.-<br /></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><span style="font-family:Courier New;color:teal;"><br /></span><span style="font-family:Comic Sans MS;font-size:9;"><strong>for (int j = 0; j < m.Length; j++)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>……<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>…<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Type[] tipos = m[j].GetTypes();<br /></strong></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>for (int i = 0; i < tipos.Length; i++)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Type esteTipo = tipos[i];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>……..<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Nuestra intencion es utilizar aquellos tipos que nos permitan instanciar directamente. Es decir clases publicas.<br /></span></p><p><span style="font-family:Trebuchet MS;">Por eso es importante saber mirar esas propiedades o atributos. Se llaman </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>IsClass</strong></span><span style="font-family:Trebuchet MS;"> e </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>IsPublic</strong></span><span style="font-family:Trebuchet MS;"> y lo usamos en:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;"><strong><span style="font-size:9;">Console.Write ("Nombre del tipo {0}. Es una clase ? {1}",nombre,</span><span style="color:red;">esteTipo.IsClass</span><span style="font-size:9;">);</span></strong></span><span style="font-family:Courier New;"><br /></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">y<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;"><strong><span style="font-size:9;">Console.WriteLine("Es publico ? {0}. ", </span><span style="color:red;">esteTipo.IsPublic</span><span style="font-size:9;">);<br /></span></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Esta es la salida por pantalla de la parte correspondiente a la información sobre los tipos que existen en el modulo<br /></span></p><p><br /> </p><p><br /> </p><p><br /> </p><h3><span style="font-family:Trebuchet MS;"><br /></span>Accediendo a los metodos<br /></h3><p><span style="font-family:Trebuchet MS;">El metodo </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>VerLosMetodosDeLosTipos</strong></span><span style="font-family:Trebuchet MS;"> nos permite ver una tecnica para acceder a los metodos de una clase pública.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Primero analizamos los atributos </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>IsClass</strong></span><span style="font-family:Trebuchet MS;"> e </span><span style="font-family:Comic Sans MS;font-size:9;"><strong>IsPublic</strong></span><span style="font-family:Trebuchet MS;"> ya mencionados antes de llamar al metodo </span><span style="font-family:Courier New;">GetMethods</span><span style="font-family:Trebuchet MS;"> de </span><span style="font-family:Courier New;">Type</span><span style="font-family:Trebuchet MS;">.-<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if( esteTipo.IsClass && esteTipo.IsPublic)<br /></strong></span></p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Podemos tambien averiguar si el metodo es público o es un detalle de implementacion que no debe exponerse al mundo:<br /></span></p><p><br /> </p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>mi[k].IsPublic<br /></strong></span></p><p><br /> </p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Esta es la salida por pantalla de la parte correspondiente a la información sobre los metodos que tiene cada clase publica dentro del modulo<br /></span></p><p><br /> </p><p><br /> </p><p><span style="font-family:Trebuchet MS;">Pero para la invocación de un método precisamos saber algo más del mismo.-<br /></span></p><p><span style="font-family:Trebuchet MS;">Por ejemplo cuales son sus parámetros y quizás cuales son los tipos de dichos parámetros.-</span><span style="font-family:Courier New;color:black;"><br /></span></p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-43981893719638858902010-11-02T04:13:00.001-07:002010-11-03T16:17:03.876-07:00SOCKETS y PORTS<span xmlns=""><p><br /></p><p><br /></p><p><br /></p><p><h1>OBJETIVO<br /></h1><p></p><p><br /></p><h2>Sockets y Ports<br /></h2><p>Un Socket es una abstracción.-<br /></p><p>Representa un punto de intercomunicación entre dos procesos (por ejemplo cliente y servidor). Los procesos pueden estar en el mismo host, nodo o computadora o en nodos diferentes.-<br /></p><p>En un host pueden correr diferentes procesos brindando diferentes servicios. Por ejemplo servicios de HTTP, de Telnet, de FTP, de SMTP, etc. Cada uno de estos procesos tiene una dirección que lo identifica unívocamente respecto de los otros. Esta dirección se llama PORT.<br /></p><p>Generalmente el servicio de HTTP se brinda en el port 80, el de Telnet en el 23, FTP en el 21 y SMTP en el 25. Decimos entonces que un PORT es una dirección relativa. Identifica al proceso pero no identifica al host en el que corre dicho proceso.<br /></p><p>En una red TCP/IP como Internet cada host tiene una identificación única llamada número IP.<br /></p><p>Un SOCKET es un número IP + un PORT. Por lo tanto es una dirección absoluta ya que identifica unívocamente un proceso en toda la red. </p><p><br /></p><h2>SOCKET<br /></h2><p>La especificación Windows Sockets define una interfaz de programación en Windows basada en el paradigma de sockets del BSD (Berkeley Software Distribution).-<br /></p><p>Esta biblioteca, escrita en lenguaje C por ingenieros, profesores y estudiantes de la Universidad de Berkeley, fue pensada para la comunicación entre procesos que se ejecutan en la misma computadora o en computadoras de una misma red.-<br /></p><p>EL software fue escrito originalmente como una API (Application Programming Interface) y el código que figura a continuación es un pequeño esqueleto que muestra como es la secuencia de inicio y cierre de un proceso de comunicación, pensando en un solo thread de ejecución:<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <sys/types.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <sys/socket.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <netinet/in.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <arpa/inet.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdio.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <stdlib.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>#include <strings.h><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int main()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Inicio<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int32_t i32SocketFD = socket(AF_INET, SOCK_STREAM, 0);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(0 == i32SocketFD)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("no se puede crear el socket");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>struct sockaddr_in stSockAddr;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bzero(&stSockAddr, sizeof(stSockAddr));<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_family = AF_INET;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_port = htons(1100);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Enlace<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(-1 == bind(i32SocketFD,(struct sockaddr*) &stSockAddr, sizeof(stSockAddr)))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error: bind fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//Escucha<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(-1 == listen(i32SocketFD, 10))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error: listen fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>for(; ;)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int32_t i32ConnectFD = accept(i32SocketFD, NULL, NULL);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if(0 > i32ConnectFD)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>printf("error accept fallido");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>exit(-1);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// acá es donde se debe escribir el código especifico ...<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>…..<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//cierre<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>shutdown(i32ConnectFD, 2);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>close(i32ConnectFD);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><h2>¿Con que contamos en C#?<br /></h2><p>En C#, encontramos la funcionalidad de esta especificación, encapsulada en una clase llamada Socket, que es la que provee los métodos para la comunicación a través de la red así como la transferencia (sincrónica o asíncrona de datos).-<br /></p><p>La clase Socket se encarga de proveer métodos y propiedades para la comunicación en red.-<br /></p><p>Lo realmente interesante de esta clase es que encapsula la complejidad de la comunicación y una vez establecida el manejo de lo entrante y saliente se hace manejando flujos (streams).-<br /></p><p>Estos flujos de comunicación pueden ser sincrónicos o asíncronos.-<br /></p><h3>Procesos de un solo thread y sincrónicos.-<br /></h3><p>Igual que en el ejemplo en lenguaje C visto al inicio de este manual, para procesos de un solo thread podemos utilizar los métodos específicos para modo de operación asíncrona: Listen(), Accept(), Bind(), Send() y Receive().-<br /></p><h4>Protocolo TCP<br /></h4><p>Estos métodos se utilizan en protocolos orientados a conexión (connection-oriented) como por ejemplo TCP.-<br /></p><p>En este caso el servidor de la comunicación puede escuchar los pedidos con el método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasslistentopic.htm">Listen</a> .-<br /></p><p>EL método Accept() procesa cualquier pedido de conexión entrante y retorna un Socket que es el que se utilizara para comunicar datos con el host remoto.-<br /></p><p>Es este Socket el que se usa para llamar a los métodos <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasssendtopic.htm">Send</a>() o <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassreceivetopic.htm">Receive</a>().-<br /></p><p>Como en el caso general se desea indicar la dirección IP y el numero de puerto, se debe llamar al método Bind(), previo a llamar a Listen().-<br /></p><p>En caso de no seguir esta secuencia, el proveedor del servicio subyacente asignara estos valores por nosotros. Es posible luego obtener la dirección IP y port asignados a nuestro Socket, del modo recién indicado.-<br /></p><p>En el caso de querer conectarse a un servidor que esta escuchando requisiciones, se debe llamar al método Connect() y luego utilizar Send() y Receive() para envío y recepción de datos.-<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// crear un socket<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// enlazar el socket que escucha<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint ep = new IPEndPoint(hostIP, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listenSocket.Bind(ep);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// escuchar<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listenSocket.Listen(backlog);<br /></strong></span></p><p><br /></p><h4>Protocolo UDP<br /></h4><p>Si usamos un protocolo como UDP (protocolo sin conexión: connectionless), entonces no es necesario "escuchar" para conectarse. El método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassreceivefromtopic.htm">ReceiveFrom</a>() es el que debe usarse para recibir los datagramas entrantes y el método <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclasssendtotopic.htm">SendTo</a>() es el que debe usarse para el envio de datagramas al host remoto.<br /></p><h3>Procesos de mas de un thread y asincrónicos.-<br /></h3><p><span style="font-family:Verdana;font-size:9;">Para procesar comunicaciones utilizando threads separados, existen una serie de mtodos pensados al efecto, es decir en un modo de operacion asincrono.-<br /></span></p><h4>Protocolo TCP<br /></h4><p>Cuando se utilizan protocolos orientados a la conexión (connection-oriented) como TCP, entonces debe utilizar los métodos Socket(), <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginconnecttopic.htm">BeginConnect</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendconnecttopic.htm">EndConnect</a>() para comenzar las tareas de conexiones con el server que atiende los pedidos.-<br /></p><p>El asincronismo en el envío y la recepción de datos (en los casos donde trabajamos con mas de un thread) necesita del uso de los métodos específicos de comunicación asincrónica. Estos son: <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginsendtopic.htm">BeginSend</a>(),<a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendsendtopic.htm">EndSend</a>() , <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginreceivetopic.htm">BeginReceive</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendreceivetopic.htm">EndReceive</a>(). Los pedidos de conexión entrante los debe procesar con los métodos: <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginaccepttopic.htm">BeginAccept</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendaccepttopic.htm">EndAccept</a>().<br /></p><p>Si estamos usando UDP entonces los métodos adecuados son para enviar datagramas son <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginsendtotopic.htm">BeginSendTo</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendsendtotopic.htm">EndSendTo</a>() y para la recepción se debe usar <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassbeginreceivefromtopic.htm">BeginReceiveFrom</a>() y <a href="ms-help://MS.NETFrameworkSDKv1.1/cpref/html/frlrfsystemnetsocketssocketclassendreceivefromtopic.htm">EndReceiveFrom</a>().<br /></p><h1>Usar un socket para comunicaciones con el protocolo HTTP<br /></h1><p>El ejemplo siguiente utiliza una clase Socket para enviar y recibir respuestas de un servidor HTTP.<br /></p><p>Pensemos en un servidor WEB que esta corriendo en algún punto de la red.<br /></p><p>El modo en el que escribimos el código requiere de algunos conceptos de cómo trabaja el protocolo HTTP, damos un repaso que consideramos adecuado.-<br /></p><h2>El protocolo HTTP<br /></h2><p>El Protocolo de Transferencia de Hipertexto (Hypertext Transfer Protocol) es un protocolo para comunicación entre un nodo cliente y otro nodo servidor.-<br /></p><p>Su uso central es en la WEB, pero aclaremos que un servidor HTTP, puede recibir pedidos y enviar información sin necesidad de la existencia de browsers. Es decir es un mecanismo de comunicación que puede llegar a utilizarse en procesos puramente batch , no solo para interactivos.-<br /></p><p>El protocolo esta montado sobre el servicio de conexión TCP/IP.<br /></p><p>HTTP se basa en sencillas operaciones de solicitud/respuesta.<br /></p><p>Un cliente establece una conexión con un servidor y envía un mensaje con los datos de la solicitud.-<br /></p><p>El servidor responde con un mensaje similar, que contiene el estado de la operación y su posible resultado.-<br /></p><p>La primera parte de una transacción HTTP es cuando un cliente crea y envia una solicitud al servidor.<br /></p><p>Por ejemplo:<br /></p><p>GET /index.html /HTTP 1.1<br /></p><p>Es una pedido absolutamente correcto para un servidor HTTP activo<br /></p><p>Existen tres verbos básicos que un cliente puede utilizar para dialogar con el servidor: GET, para recoger un objeto, POST, para enviar información al servidor y HEAD, para solicitar las características de un objeto (por ejemplo, la fecha de modificación de un documento HTML).<br /></p><p>Todas las operaciones pueden adjuntar un objeto o recurso sobre el que actúan; cada objeto Web (documento HTML, fichero multimedia o aplicación CGI) es conocido por su URL (Uniform resources location podría concebirse como la extensión del concepto de nombre completo de un archivo (path)).<br /></p><p>Cada operación HTTP implica una conexión con el servidor, que es liberada al término de la misma. (Esa es la verdadera esencia de Internet ¡!)<br /></p><p>Es decir, en una operación se puede recoger un único objeto y no se mantienen estados.<br /></p><p>Cada petición de un cliente a un servidor no es influida por las transacciones anteriores. El servidor trata cada petición como una operación totalmente independiente del resto.<br /></p><p>El acceso a los servidores HTTP se realiza a través de las URLs, que empaquetan toda la información necesaria para localizar un determinado recurso en Internet. Cuando el servidor recibe una URL, a través del protocolo HTTP, la decodifica y devuelve al cliente la información correspondiente, que puede ser de dos tipos, en función del contenido de la URL:<br /></p><p>Información estática: que se publica a base de situar los ficheros que la contienen en unos directorios especiales que define cada servidor. Este es el procedimiento que se ha utilizado hasta ahora.<br /></p><p>Información dinámica: en este caso, el servidor HTTP arranca una aplicación utilizando la propia URL como parámetro de ejecución. El resultado de la ejecución de la aplicación será devuelto al cliente<br /></p><p>El término 'información dinámica' se amplia cada vez más, a medida que se dispone de nuevas aplicaciones y tecnologías de publicación de información.<br /></p><p>A través de estas nuevas tecnologías, es posible generar vistas a través del Web de elementos tan dispares como hojas de cálculo, bases de datos, agendas de reuniones, correos electrónicos e incluso periódicos completos, que se actualizan automáticamente en función de los cambios en el contenido de información original.<br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.IO;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net.Sockets;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public class mySocket<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static Socket connectSocket(string server, int port)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket s = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPHostEntry iphe = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>iphe = Dns.Resolve(server);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Esta iteracion a traves de la lista de direcciones ( AddressList) es para obtener la<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//llamada familia de direcciones ( AddressFamily) soportada.Esto evitara una excepcion en el caso<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//en que la dirección IP no sea compatible con dicha familia.-<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>foreach (IPAddress ipad in iphe.AddressList)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint ipe = new IPEndPoint(ipad, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket tmpS =<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>tmpS.Connect(ipe);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (tmpS.Connected)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>s = tmpS;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (SocketException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("SocketException !!!");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Origen : " + e.Source);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Mensaje : " + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (Exception e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Exception atrapada!!!");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Origen : " + e.Source);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine("Mensaje : " + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return s;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// este método consulta el contenido de la pagina Home del servidor indicado.<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// y muestra el contenido recibido<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static string socketSendReceive(string server, int port)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>//Preparamos para escribir al server<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Encoding ASCII = Encoding.ASCII;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string Get = "GET / HTTP/1.1\r\nHost: " + server +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"\r\nConnection: Close\r\n\r\n";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Byte[] ByteGet = ASCII.GetBytes(Get);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Byte[] RecvBytes = new Byte[256];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String strRetPage = null;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Ahora creamos un socket como conneccion con el server y el port indicado<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket s = connectSocket(server, port);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (s == null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return ("Conneccion fallida");<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Ahi viaja el pedido al servidor.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>s.Send(ByteGet, ByteGet.Length, 0);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Aca viene la respuesta de la pagina home del server<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Leer los primeros 256 bytes.Esto lo determina el uso de<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//RecvBytes.Length en el método Receive<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = "Pagina Default HTML en el " + server + ":\r\n";<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>while (bytes > 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>return strRetPage;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public static void Main(string[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string host;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int port = 91;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (args.Length == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// si no hay server indicado, usamos el nombre del host.<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>host = Dns.GetHostName();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>host = args[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string result = socketSendReceive(host, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Console.WriteLine(result);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p>Vamos a hacer la prueba de este programa conectándolo contra un server WEB TOMCAT.<br /></p><p><br /></p><p>En mi equipo, como se observa, esta levantado en el puerto 8088.-<br /></p><p>Si ejecuto el programa, colocando como parámetro en la línea de ejecución del programa, esta dirección.<br /></p><p><br /></p><h1><span style="font-size:10;">Y lo ejecutamos, vemos la salida de texto que se muestra a continuación:<br /></span></h1><p><br /></p><p>Por supuesto que es mejor verla con el browser ¡!<br /></p><p><br /></p><p><h1>Usar sockets para armar un programa de mensajería entre pares (chat)<br /></h1><p></p><p>Vamos a construir una aplicación Windows que nos entregue una interfaz simple para comunicación. Queremos que sea un contenedor con dos paneles.<br /></p><p>Uno que me muestre los mensajes que recibo y el otro que me permita escribir mensajes.-<br /></p><p>La propia aplicación trabajara de dos modos diferenciados dependiendo de cómo se la invoque en la llamada. En un caso será servidor y en otro cliente.-<br /></p><p>Alcanza con solo servidor para atender múltiples clientes.-<br /></p><p>El esquema que armamos es el de "estrella". Es decir tal como armamos la aplicación todos los clientes pueden hablar con el servidor, pero no entre si.-<br /></p><p>Una variante de este modo en el que el servidor atrape el pedido y lo derive u otro cliente de la red es relativamente sencillo de hacer basado en la tecnología mostrada en este ejemplo.-<br /></p><p><br /></p><p>Se habrá creado un proyecto con una serie de componentes como muestra el grafico<br /></p><p><br /></p><p>En este tipo de aplicaciones dentro del Form (Form1.cs), la IDE de .NET escribe algunos códigos de inicialización que no queremos para nuestro caso.-<br /></p><h2>Codigo en Form1.cs<br /></h2><p>Ingrese a código de Form1.Designer.cs y reemplácelo por el código que figura a continuación:<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>namespace UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>partial class Form1<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// <summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// Required designer variable.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// </summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private System.ComponentModel.IContainer components = null;<br /></strong></span></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>#region Windows Form Designer generated code<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// <summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// Required method for Designer support - do not modify<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// the contents of this method with the code editor.<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>/// </summary><br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>private void InitializeComponent()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>{<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>#endregion<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;color:blue;"><strong>}<br /></strong></span></p><p><br /></p><h2>Código en program.cs<br /></h2><p>Reemplace el código del modulo program.cs por el código que figura a continuación<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Windows.Forms;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Globalization;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">using</span> System.Net.Sockets;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><span style="color:blue;">namespace</span> UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">static</span><br /><span style="color:blue;">class</span><br /><span style="color:teal;">Program<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// -<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:teal;">IPEndPoint</span> endPoint;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">//Indica si esta actuando en modo servidor o cliente<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">bool</span> client;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Entrada al programa<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">public</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">void</span> Main(<span style="color:teal;">String</span>[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// -<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (ParseArgs(args))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">//<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">Talker</span> talker = <span style="color:blue;">new</span><br /><span style="color:teal;">Talker</span>(endPoint, client);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Referencia del Talker dentro del Form<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">TalkForm</span> form = <span style="color:blue;">new</span><br /><span style="color:teal;">TalkForm</span>(talker);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Arranca el talker<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>talker.Start();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Arranca la apliacion con el Form<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">Application</span>.Run(form);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:green;">// Parser de la linea de comandos<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">private</span><br /><span style="color:blue;">static</span><br /><span style="color:blue;">bool</span> ParseArgs(<span style="color:teal;">String</span>[] args)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">try<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">IPAddress</span>.Any, 5150);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args[0][0] != <span style="color:maroon;">'/'</span> && args[0][0] != <span style="color:maroon;">'-'</span>)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">switch</span> (<span style="color:teal;">Char</span>.ToUpper(args[0][1], <span style="color:teal;">CultureInfo</span>.InvariantCulture))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">case</span><br /><span style="color:maroon;">'L'</span>: <span style="color:green;">//Listen: Escucha<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">int</span> port = 5150;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length > 1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = <span style="color:teal;">Convert</span>.ToInt32(args[1]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">IPAddress</span>.Any, port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">break</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">case</span><br /><span style="color:maroon;">'C'</span>:<span style="color:green;">//Call: Llama<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = 5150;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:teal;">String</span> address = <span style="color:maroon;">"127.0.0.1"</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = <span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">if</span> (args.Length > 1)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>address = args[1];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>port = <span style="color:teal;">Convert</span>.ToInt32(args[2]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = <span style="color:blue;">new</span><br /><span style="color:teal;">IPEndPoint</span>(<span style="color:teal;">Dns</span>.GetHostEntry(address).AddressList[0], port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">break</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">default</span>:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">catch<br /></span></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ShowUsage();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">false</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">return</span><br /><span style="color:blue;">true</span>;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Como se usa<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private static void ComoUsarme()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /><span style="color:blue;">MessageBox.Show</span>("UnChat [switch] [parametros...]\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>" /L [port]\t\t-- Escucha en el port. Default: 5150\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>" /C [direccion] [port]\t-- Conecta a una direccion y port.\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Ejemplo Server - \n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"UnChat /L\n\n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Ejemplo Client - \n" +<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"UnChat /C NombreDeServidor 5150", "Uso de UnChat");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><h2>Código en Talker.cs<br /></h2><p><br /></p><p>Creemos ahora la clase que representara al Talker<br /></p><p><br /></p><p><br /></p><p>Y coloquemos dentro del archivo de esta clase el código que se indica a continuación:<br /></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Collections.Generic;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Text;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Net.Sockets;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.IO;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>using System.Threading;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>namespace UnChat<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Esta clase es una capa que encpasula a la clase Socket y le agrega<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// algunas habilidades de chateo.-<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>class Talker : IDisposable<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private Socket socket;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private TextReader reader;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private TextWriter writer;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>bool client;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>IPEndPoint endPoint;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String prevSendText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String prevReceiveText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private String statusText;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private Status status;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Constructor<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public Talker(IPEndPoint endPoint, bool client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.endPoint = endPoint;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.client = client;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = null;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>statusText = prevSendText = prevReceiveText = String.Empty;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// -<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>~Talker()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Dispose();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Este es un modo ordenado y seguro de liberar todos<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//los recursos que se usaron en el momento en que se baja<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>//la aplicacion<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void Dispose()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>GC.SuppressFinalize(this);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (reader != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (writer != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (socket != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Clase delegate y evento<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public delegate<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>void NotificationCallback(Notification notify, Object data);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public event NotificationCallback Notifications;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// enum de los tipos de notificaciones<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public enum Notification<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Initialized = 1,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>StatusChange,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceivedRefresh,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceivedAppend,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>End,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Error<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// enum de los posibles estados<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public enum Status<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Escuchando,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Conectado,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Cliente<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// EL inicio de una instancia de la clase es un thread<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//que se encola en el pool de threads<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void Start()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ThreadPool.QueueUserWorkItem(new WaitCallback(EstablishSocket));<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Envio de texto a la coneccion remota<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>public void EnviaMensaje(String newText)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String send;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// es un agregado al texto (append)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if ((prevSendText.Length <= newText.Length) && String.CompareOrdinal(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>newText, 0, prevSendText, 0, prevSendText.Length) == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>String append = newText.Substring(prevSendText.Length);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>send = String.Format("A{0}:{1}", append.Length, append);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}// o reemplazo completo<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>send = String.Format("R{0}:{1}", newText.Length, newText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Envio datos y hace flush<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Write(send);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Flush();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Guardar el texto para comparar si es necesario<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevSendText = newText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Notifica un estado<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void SetStatus(Status status)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>this.status = status;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.StatusChange, status);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Establecer una coneccion via socket y comenzar la recepcion<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void EstablishSocket(Object state)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>NetworkStream stream = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>// Si no es un cliente, entonces levantar una Escucha (listener)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (!client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket listener;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener = new Socket(AddressFamily.InterNetwork,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Blocking = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Bind(endPoint);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Escuchando);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Listen(0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = listener.Accept();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>listener.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stream = new NetworkStream(socket);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = new StreamReader(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = new StreamWriter(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Write("WINTALK .NET");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer.Flush();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (SocketException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Este error indica que alguien esta usando el puerto<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//Asumamos que en ese caso se debe intentar conectarse como un cliente<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//pensando que ya hay un server para los nodos de la red<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (e.ErrorCode == 10048)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>client = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>endPoint = new IPEndPoint(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Dns.Resolve("127.0.0.1").AddressList[0], endPoint.Port);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notification.Error,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Error al inicializar el Socket:\n" + e.ToString());<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Intenta coneccion como cliente<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (client)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Cliente);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket temp = new<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Socket(AddressFamily.InterNetwork,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketType.Stream, ProtocolType.Tcp);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>temp.Blocking = true;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>temp.Connect(endPoint);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = temp;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>stream = new NetworkStream(socket);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader = new StreamReader(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>writer = new StreamWriter(stream);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] handshake = new char[12];<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>try<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>reader.Read(handshake, 0, 12);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string sHandShake = new string(handshake);<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (!(reader.Read(handshake, 0, 12) > 0 && sHandShake == "WINTALK .NET"))<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 0);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket.Close();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>socket = null;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Si establecimos el socket, comenzar a chatear<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (socket != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SetStatus(Status.Conectado);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Initialized, this);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">// -<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//NetworkStream.Read()es un metodo llamado por el metodo ReceiveTalk<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//El primer metodo genera una excepcion cuando se cierra la coneccion remota<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//La excepcion se maneja en el catch<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>ReceiveTalk();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;">// Por aca pasa cuando NetworkStream.Read() retorna un cero (algo que hace<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;">//en alguans versiones del SO<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.End, "La coneccion remota se cerro.");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error,<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>"Falla al establecer el , Verifique si especifico el port correcto");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (IOException e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>SocketException sockExcept = e.InnerException as SocketException;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (sockExcept != null && 10054 == sockExcept.ErrorCode)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.End, "La coneccion remota se cerro.");<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (Notifications != null)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error, "Error :\n" + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>catch (Exception e)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.Error, "Error:\n" + e.Message);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong><br /></strong>// Recibe la comunicacion del cliente remoto<br /></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>private void ReceiveTalk()<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] commandBuffer = new char[20];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>char[] oneBuffer = new char[1];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int readMode = 1;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>int counter = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>StringBuilder text = new StringBuilder();<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>while (readMode != 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (reader.Read(oneBuffer, 0, 1) == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>switch (readMode)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 1:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (counter == commandBuffer.Length)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (oneBuffer[0] != ':')<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>commandBuffer[counter++] = oneBuffer[0];<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>counter = Convert.ToInt32(<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>new String(commandBuffer, 1, counter - 1));<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (counter > 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 2;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>text.Length = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>else if (commandBuffer[0] == 'R')<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>counter = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText = String.Empty;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedRefresh, prevReceiveText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 2:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>text.Append(oneBuffer[0]);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>if (--counter == 0)<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>switch (commandBuffer[0])<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>{<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>case 'R':<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText = text.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedRefresh, prevReceiveText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>default:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>string newText = text.ToString();<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>prevReceiveText += newText;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>Notifications(Notification.ReceivedAppend, newText);<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 1;<br /></strong></span></p><p><br /></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>break;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>default:<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>readMode = 0;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>continue;<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><p><span style="font-family:Comic Sans MS;font-size:9;"><strong>}<br /></strong></span></p><h2>Como ejecutar la aplicación<br /></h2><p><br /></p><p>Usar una sesión como cliente y otra como servidor<br /></p><p>Para eso generar dos archivos .bat (llamémoslos ChatCliente.bat y ChatServer.bat) que inicien cada uno una sesión del programa<br /></p><p><br /></p><p>Por ejemplo para <strong>ChatCliente.bat</strong><br /></p><p>UnChat.exe /C m3nb02 5150<br /></p><p>Que significa que el programa desea actuar como Cliente (de allí la letra C) del equipo <strong>m3nb02</strong> (es el nombre de mi equipo en esta red en la que estoy trabajando) y "hablar" por el port 5150.-<br /></p><p><br /></p><p>Por ejemplo para <strong>ChatServer.bat</strong><br /></p><p><br /></p><p>UnChat.exe /L 5150<br /></p><p>Que significa que el programa desea actuar como Server (La letra L por Listen) y "hablar" por el port 5150.-<br /></p><p><br /></p><h2>Sockets y Ports<br /></h2><h2>El protocolo FTP<br /></h2><p>Codigos de retorno de FTP<br /></p><div><table style="BORDER-COLLAPSE: collapse" border="0"><colgroup><col style="WIDTH: 42px"><col style="WIDTH: 554px"></colgroup><tbody valign="top"><tr style="BACKGROUND: #f2f2f2"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: #aaaaaa 0.75pt solid; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;"><strong>Code</strong></span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: #aaaaaa 0.75pt solid; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p style="TEXT-ALIGN: center"><span style="font-family:Times New Roman;font-size:12;"><strong>Explanation</strong></span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">100</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Series: The requested action is being initiated, expect another reply before proceeding with a new command.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">110</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Restart marker replay . In this case, the text is exact and not left to the particular implementation; it must read: MARK yyyy = mmmm where yyyy is User-process data stream marker, and mmmm server's equivalent marker (note the spaces between markers and "=").</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">120</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service ready in nnn minutes.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">125</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Data connection already open; transfer starting.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">150</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">File status okay; about to open data connection.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">200</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command okay.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">202</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented, superfluous at this site.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">211</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">System status, or system help reply.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">212</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Directory status.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">213</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">File status.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">214</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Help message.On how to use the server or the meaning of a particular non-standard command. This reply is useful only to the human user.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">215</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">NAME system type. Where NAME is an official system name from the list in the Assigned Numbers document.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">220</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service ready for new user.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">221</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service closing control connection.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">225</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Data connection open; no transfer in progress.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">226</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Closing data connection. Requested file action successful (for example, file transfer or file abort).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">227</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Passive Mode (h1,h2,h3,h4,p1,p2).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">228</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Long Passive Mode (long address, port).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">229</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Entering Extended Passive Mode (port).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">230</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User logged in, proceed. Logged out if appropriate.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">231</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User logged out; service terminated.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">232</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Logout command noted, will complete when transfer done.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">250</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action okay, completed.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">257</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">"PATHNAME" created.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">331</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">User name okay, need password.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">332</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Need account for login.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">350</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action pending further information</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">421</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Service not available, closing control connection. This may be a reply to any command if the service knows it must shut down.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">425</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Can't open data connection.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">426</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Connection closed; transfer aborted.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">434</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested host unavailable.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">450</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action not taken.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">451</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action aborted. Local error in processing.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">452</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. Insufficient storage space in system.File unavailable (e.g., file busy).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">500</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Syntax error, command unrecognized. This may include errors such as command line too long.</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">501</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Syntax error in parameters or arguments.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">502</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">503</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Bad sequence of commands.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">504</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Command not implemented for that parameter.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">530</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Not logged in.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">532</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Need account for storing files.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">550</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. File unavailable (e.g., file not found, no access).</span></p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">551</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action aborted. Page type unknown.</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">552</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested file action aborted. Exceeded storage allocation (for current directory or dataset).</span> </p></td></tr><tr style="BACKGROUND: #f9f9f9"><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: #aaaaaa 0.75pt solid; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">553</span> </p></td><td style="BORDER-RIGHT: #aaaaaa 0.75pt solid; PADDING-RIGHT: 3px; BORDER-TOP: medium none; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; BORDER-LEFT: medium none; PADDING-TOP: 3px; BORDER-BOTTOM: #aaaaaa 0.75pt solid" valign="center"><p><span style="font-family:Times New Roman;font-size:12;">Requested action not taken. File name not allowed.</span> </p></td></tr></tbody></table></div><p><br /></p></span>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-72404198646088945592010-08-08T15:43:00.000-07:002010-08-08T15:48:15.175-07:00clases abstractas, Interfaces y enumeraciones PARTE II<a name="_Toc162421790">LA IMPLEMENTACION</a><br />Creemos un proyecto de consola:<br /><br />Y generemos en el 4 módulos denominados AnalizaArgumentos, Analizador, OcurrenciaPalabra y WordCount.-<br />El código de las clases que se montan en cada modulo esta en las paginas siguientes.-<br />Luego para utilizarlo genere archivos de texto e invoque en la línea de comandos a los mismos con las opciones que desee.-<br /><br /><br />Por ejemplo colocando esto en la ventana de propiedades del proyecto en la opción DEBUG:<br />-a -o Texto.txt Conecciones.txt -fSalida.txt<br /><br /><br />Esto es interpretado por el programa asi:<br />-a: Un switch que significa ORDENADO ALFABETICAMENTE<br /><br /><br />-o: Un switch que significa ORDENADO por OCURRENCIA y luego ALFABETICAMENTE<br /><br /><br />Texto.txt Conecciones.txt: Son dos archivos de texto, que estan en el paso de ejecucion (o en el directorio de trabajo en el que estamos ya que en el ejemplo marcamos C:\M3)<br /><br /><br />-fSalida.txt: Es un archivo de salida de la información que genera WordCount. La alternativa por defecto es la pantalla de texto.-<br /><br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiehKw_wcaaZFTuySPffikaV9QyIcfEa9NDRt42lw8TcaIU9v51oR-qdg7gAsSasyQ7zTwpEg9srkijuQfS-aHj4sBNkYNiyKyCVIrd8uzJZ3XJVJjwTNC1-S0Pxkhr9cOu05oHLUliiDo/s1600/Proy.jpg"><img id="BLOGGER_PHOTO_ID_5503173679811467714" style="WIDTH: 320px; CURSOR: hand; HEIGHT: 234px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiehKw_wcaaZFTuySPffikaV9QyIcfEa9NDRt42lw8TcaIU9v51oR-qdg7gAsSasyQ7zTwpEg9srkijuQfS-aHj4sBNkYNiyKyCVIrd8uzJZ3XJVJjwTNC1-S0Pxkhr9cOu05oHLUliiDo/s320/Proy.jpg" border="0" /></a><br /><br /><br /><a name="_Toc162421791">La clase Abstracta Analizador</a><br />/*=====================================================================<br />Archivo: Analizador.cs<br />Esta clase tiene el cuerpo basico para trabajar como un analizador de<br />* argumentos para un programa que admite parametros en su invocacion<br />* desde la linea de comandos. Los parametros, se asume, comienzan con<br />* llaves (switchs) que indican alguna particularidad del mismo.<br />* Un ejemplo valido seria<br />* c:\prog1.exe -eArchivo.txt -sSalida.txt<br />* Donde prog1.exe es el programa que se ejecuta y tanto -eArchivo.txt<br />* como -sSalida.txt son los argumentos<br />* -e (antes de Archivo.txt) y -s (antes de Salida.txt) son las llaves.<br />*<br /><br /><strong><em><span style="font-size:85%;">=====================================================================*/<br /><br />//<br />using System;<br />using System.Globalization;<br /><br /><br />///////////////////////////////////////////////////////////////////////////////<br /><br /><br />public abstract class Analizador {<br />private String[] separadores; // Por defecto: "/", "-"<br />private String[] argumentos; // Estos son los argumentos validos<br />//que el analizador debe reconocer<br />private Boolean argSensiblesAMayOMin; // Indica si los argumentos deben ser sensibles a Mayusculas/Minusculas<br /><br /><br />//<br />protected enum SwitchStatus { NoError, Error, ShowUsage };<br /><br /><br />// Constructor 1<br />public Analizador(String[] switchSymbols)<br />: this(switchSymbols, false, new string[] { "/", "-" }) {<br />}<br /><br /><br />// Constructor 2<br />public Analizador(String[] switchSymbols, Boolean caseSensitiveSwitches)<br />: this(switchSymbols, caseSensitiveSwitches, new string[] { "/", "-" }) {<br />}<br /><br /><br />// Constructor 3, sin valores por defecto<br />public Analizador(String[] _argumentos, Boolean _argSensiblesAMayOMin, String[] switchChars)<br />{<br />this.argumentos = _argumentos;<br />this.argSensiblesAMayOMin = _argSensiblesAMayOMin;<br />this.separadores = switchChars;<br />}<br /><br /><br />// -<br />public abstract void ModoDeUso(String errorInfo);<br /><br /><br /><br />protected virtual SwitchStatus OnSwitch(String switchSymbol, String switchValue) {<br />return(SwitchStatus.Error);<br />}<br /><br /><br /><br />// Cada clase derivada debe implementar el metodo OnNonSwitch<br />//observe que sino por defecto un switch se considera un error<br />protected virtual SwitchStatus OnNonSwitch(String value) {<br />return(SwitchStatus.Error);<br />}<br /><br /><br />// Informamos a la clase derivada despues que se hizo todo el analisi<br />// -<br />protected virtual SwitchStatus OnDoneParse() {<br />// -<br />return(SwitchStatus.Error);<br />}<br /><br /><br />// Solo sabemos analizar argumentos de la linea de comandos<br />public Boolean Parse() {<br />return(Parse(Environment.GetCommandLineArgs()));<br />}<br /><br /><br />// Este es el analizador<br />public Boolean Parse(String[] args) {<br />SwitchStatus ss = SwitchStatus.NoError; //<br /><br />int ArgNum;<br />for (ArgNum = 0; (ss == SwitchStatus.NoError) && (ArgNum < fisswitch =" false;" n =" 0;" fisswitch =" (0" flegalswitchsymbol =" false;" n =" 0;" flegalswitchsymbol =" (0" flegalswitchsymbol =" (0"> salir<br />if (!fLegalSwitchSymbol) {<br /><br />ss = SwitchStatus.Error;<br />break;<br />} else {<br />// Switch valido -> notificar a la clase derivada el switch y su valor<br />ss = OnSwitch(<br />argSensiblesAMayOMin ? argumentos[n] : argumentos[n].ToLower(CultureInfo.InvariantCulture),<br />args[ArgNum].Substring(1 + argumentos[n].Length));<br />}<br />}<br />else // Esto no es un switch, retornar a la clase derivada para que lo analice<br />{<br />ss = OnNonSwitch(args[ArgNum]);<br />}<br />}<br /><br />// Fin del analisis de los argumentos<br />if (ss == SwitchStatus.NoError) {<br />// -<br />ss = OnDoneParse();<br />}<br /><br />if (ss == SwitchStatus.ShowUsage) {<br />//<br />ModoDeUso(null);<br />}<br /><br />if (ss == SwitchStatus.Error) {<br />//<br />ModoDeUso((ArgNum == args.Length) ? null : args[ArgNum]);<br />}<br /><br />// -<br />return(ss == SwitchStatus.NoError);<br />}<br />}<br /><br /><br />///////////////////////////////// End of File /////////////////////////////////</span></em></strong>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-69203185006505151492010-08-08T15:11:00.000-07:002010-08-08T15:36:06.614-07:00clases abstractas, Interfaces y enumeraciones-PARTE I<a name="_Toc162421787"><span style="font-size:130%;"><strong>OBJETIVO </strong></span></a><br /><br />Vamos a hacer un ejercicio clásico: Un programa que lee un archivo de texto y cuenta los caracteres, palabras y líneas que hay en el.-<br />Este programa clasico suele llamarse (como era de esperar) WordCount y su ductilidad es tal que permite utilizar muy distintas estructuras de datos para lograr el cometido.-<br />En nuestro caso pondremos el acento en generar una clase abstracta que se encargara de analizar la entrada que acompaña a la invocación del programa (los argumentos de línea de comando).-<br />Por otro lado utilizaremos unas interfaces útiles para el tipo de estructura de datos que nos interesa utilizar.-<br />Creemos que WordCount al ser un programa clásico de algoritmos permite visualizar aspectos poderosos de la programación orientada a objetos así como sacar provecho de algunas de las bibliotecas estándar de C#.-<br /><br /><br /><br /><br /><a name="_Toc162421788"><span style="font-size:130%;"><strong>El requerimiento funcional</strong></span></a><br /><br />WordCount es un programa que:<br />A) Debe tomar como entrada un archivo de texto.Entiendase por esto que puede elegir distintos CodePages (encoding) pero que el archivo en si debe ser un flujo de caracteres en el que exista el concepto de palabra como unidad de construcción<br />B) De esa entrada debe producir un conteo:<br />· Lineas (grupos de caracteres separados por “nueva linea”).-<br />· Palabras (grupos de caracteres entre separadores de texto).-<br />· Caracteres (son los que conforman las palabras y los separadores de texto).-<br />· Bytes (son los caracteres mas las “nueva linea”).-<br />C) La salida dr la información puede ser por consola o puede ser hacia un archivo (de texto) que debera ser especificado.-<br />D) La salida admite ciertos ordenamientos:<br />· Por palabra indicando la cantidad de ocurrencias de la misma<br />· Por ocurrencia y luego alfabeticamente por palabra<br />E) La aplicación sera una aplicación de consola por lo que desde la linea de comandos debe poder especificarse lo que se desea que realice la aplicación. No se desea que la aplicación necesite de un archivo de propiedades dado que su funcionalidad es reducida y se adecua a recibir parametros dedes la linea de comandos del sistema operativo.-<br /><br /><a name="_Toc162421789"><strong><span style="font-size:130%;">Mapeo de funcionalidad con mi toolbox:</span></strong></a><br /><br /><br /><br /><br />Este problema nos pone frente a una variedad de situaciones conocidas que enunciaremos como lista de requerimientos y funcionalidades que la aplicación debe tener. A cada comentario de funcionalidad mapearemos una tecnica o modo de resolucion. Esta es una buena practica para cualquier programador que permite probar la riqueza del lenguaje que utiliza asi como las bibliotecas y el Framework sobre el que esta trabajando.-<br /><br /><br /><br /><br />Siendo esta aplicación de consola, manejando caracteres y esencialmente algoritmica, veremos que las colecciones e interfases del CLR de .NET haran gran parte del trabajo.-<br /><br /><br /><br /><br />1- Analisis de parametros recibidos desde la linea de comando. Es una aplicación de consola sin interfaz grafica con el usuario. De modo que parece razonable utilizar parametros desde la linea de comandos en vez de utilizar un archivo de propiedades. Al fin de cuentas no son tantas las propiedades de configuracion que la aplicación deba contemplar.-<br />Como estamos acostumbrados a que estos parametros sean letras precedidas por separadores (como por ejempo leerdatos.exe –ac:\datos.txt –fc:\analisis.prn) haremos que esta clase sea una base utilizable para tareas similares.-<br />Cada letra indica una posible accion de la aplicación y es posible que exista una combinacion de letras, por lo que la tarea basica del analizador (Parser) es trabajar con separadores y argumentos y retornar arrays de estas categorias para que el programa que usa estos servicios pueda realizar su tarea especifica de interpretacion de los parametros y las llaves.-<br />Sin embargo esta clase no podra resolver todos los casos que plantee el analisis de argumentos, aun cuando usemos el esquema simple de llaves(switchs) y argumentos.<br />Por otro lado si pensamos en una interfaz, solo enunciaremos los metodos y deberemos escribir en cada implementacion codigo que es comun.-<br />Es decir una clase no nos resuelve todos los casos y una interfaz no cumple una funcion util.-<br />Para eso vamos a hacer una clase abstracta que hara las tareas de analisis de parametros en una linea de comandos.-<br />Esta es la real utilidad de una clase abstracta: Presentar la posibilidad de herencia de los propios metodos de la clase, tener metodos que deben ser escritos por el implementador de la clase que hereda, Y NO PERMITIR LA INSTANCIACION DIRECTA.<br />Es decir no podemos hacer<br /><br /><br /><br /><br />MiClaseAbstracta ca = new MiClaseAbstracta();<br /><br /><br /><br /><br />Este no es un detalle menor como elección de ingeniería. Al no permitir la instanciación directa obliga a que otra clase:<br />Herede :usando lo que ya esta definido y es común.-<br />Redefina : (override)<br /><br />2- Lectura desde un flujo plano de caracteres. Esto es leer un archivo de texto. Esta tarea la realizaremos con la clase FileStream del namespace FileStream y un lector de flujo (StreamReader):<br /><br />FileStream fsIn = new FileStream(pathname, FileMode.Open, FileAccess.Read, FileShare.Read);<br /><br />StreamReader sr = new StreamReader(fsIn, fileEncoding, true);<br /><br />3- Los archivos que leeremos como entrada debemos colocarlos en un contenedor (Un array de strings que implementaremos como un ArrayList:<br />private ArrayList archivosALeer = new ArrayList();<br /><br />4- Este arreglo deberá después enviarse de algún modo al programa que llama de modo que pueda barrer esa lista de archivos e ir procesándolos y llevando su estadística de líneas, palabras, etc.<br />Acá es valido pensar en un getter que devuelva dicho array al programa para que opere sobre el o bien utilizar una Interfaz de enumeración.<br />Esta es una aproximación muy interesante al problema que nos permite devolver el enumerador de esa colección y luego el programa que llama se encarga de iterar sobre dicho enumerado y tomar su valor asociado. Esto permite que si luego internamente en la clase que implementa lo indicado en el punto 3, deseamos cambiar la estructura, el programa que llama no se entera ya que el siempre barrera un iterador.-<br /><br />// Retorna un enumerator incluyendo todos los archivos indicados<br />public IEnumerator GetEnumeradorDeArchivos() {<br />return archivosALeer.GetEnumerator(0, archivosALeer.Count);<br />}<br />IEnumerator que es la interfaz que aquí utilizamos es la Interfaz base de todas las enumeraciones genéricas.-<br />5- Analizador de cada línea leída, cortando esa línea en palabras. Este es un algoritmo clásico en el que el concepto de palabra es el conjunto consecutivo de caracteres entre separadores. Los separadores son los propios del sistema LEXICO que se esta utilizando (lo que en jerga técnica se llama ENCODING o CONJUNTO DE CARACTERES). Observemos que esto implica que para un lenguaje dado, existe un sistema LEXICO dado (un ENCODING) y por lo tanto un conjunto de separadores ya definidos que es el aceptado por los lenguajes que usan dicho ENCODING.-<br />Esta tarea es habitual y en las clases de C# (en realidad en las de .NET y el CLR) tenemos funcionalidad de cortar una línea de textos en palabras (String.Split()) que contiene todo lo que necesitamos para realizar esta tarea de separación.-<br />6- Necesitamos un contenedor especial: Un diccionario. Este es un contenedor de dos posiciones. Una es la clave y la otra el valor que nos interesa. Esta estructura de datos es de utilidad para llevar la cuenta de palabras encontradas que es uno de los objetivos primarios de la aplicación.<br />El Diccionario es un contenedor clásico y en las bibliotecas de .NET y el CLR tenemos una implementación de especial utilidad denominada SortedList.-<br /><br />// La lista de palabras (ordenada alfabeticamente)<br />System.Collections.SortedList ctdorDePalabras = new SortedList();<br />Lo interesante de este contenedor es que es una implementación de una interfaz genérica denominada IDictionary. Esta interfaz es la base de todas aquellas estructuras que deban cumplir el patrón: par clave/valor.-<br />Otra característica interesante de este contenedor es que también es una implementación de la Interfaz de listas no genéricas (IList). Esto nos permite tener en el mismo constructor las facilidades de agregar un par clave/valor del diccionario, asi como las búsquedas de inclusión que tienen las listas.-<br />Advertencia: No esta demás decir que tanta funcionalidad es al precio de la performance. Sea cauto en el uso de SortedList para implementación de par/valor. En otros casos un HashTable puede ser más eficiente en términos de velocidad. Acá elegimos las SortedList ya que se adecuan a las necesidades de ordenamiento<br /><br />7- El ordenamiento solicitado de las listas que contienen las palabras leídas y sus ocurrencias, se ha solicitado de modo doble: A) Alfabéticamente y B) Por Ocurrencia y Alfabéticamente.-<br />Esto nos propone una idea: Que exista una clase que exprese la ocurrencia de las palabras y que sirva para que nuestra lista resulte ordenada según las reglas del punto B) (por ocurrencia y alfabéticamente). Siendo que las listas se armaran como SortedLIst que es una lista ordenada, resulta necesario que esta clase que vamos a crear tenga alguna relación con SortedList.<br />Es aquí donde comienza a jugar un papel importante la idea de polimorfismo. SortedList implementa entre otras cosas la interfaz IComparable. Esta interfaz tiene un método virtual llamado CompareTo que implementa.<br /><br />Para entender como enlazar todo esto veamos lo que dicen los ingenieros que implementaron SortedList:<br /><br /><br /><em>Lo elementos de una SortedList estan ordenados por sus claves, ya sea de acuerdo a una implementacion de </em><a href="http://msdn2.microsoft.com/en-us/library/system.collections.icomparer(VS.71).aspx"><em>IComparer</em></a><em> especificada cuando se crea la SortedList o de acuerdo a una implemenatcion de </em><a href="http://msdn2.microsoft.com/en-us/library/system.icomparable(VS.71).aspx"><em>IComparable</em></a><em> provista por las claves mismas. En ambos casos una SortedList no permite la duplicacion de llaves.</em><br /><br /><br />Esto significa que podemos resolver el tema de ordenamiento por ocurrencia y alfabéticamente haciendo una clase que IMPLEMENTE IComparable y que se creen objetos que sean de dicha clase:<br /><br /><br />public class OcurrenciaPalabra : IComparable<br />{<br />….<br />}<br /><p><br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoru42TkoE4wLpqHqZkM0tn2_onQKlOgLRLPqYS3wYxIjiGsT6qYkDXiehpL1v8O-SHg5D-xBmeeQ9SHlMFyE8HDtLhIGvyVauHFalYjBumLBhZGqfS7_XSGZkO5i21InXUT1ZimUOhHk/s1600/SortedList.bmp"><img id="BLOGGER_PHOTO_ID_5503168717419938162" style="WIDTH: 444px; CURSOR: hand; HEIGHT: 291px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoru42TkoE4wLpqHqZkM0tn2_onQKlOgLRLPqYS3wYxIjiGsT6qYkDXiehpL1v8O-SHg5D-xBmeeQ9SHlMFyE8HDtLhIGvyVauHFalYjBumLBhZGqfS7_XSGZkO5i21InXUT1ZimUOhHk/s400/SortedList.bmp" border="0" /></a> </p><p>1- Para mostrar la información solicitada es necesario barrer las listas ordenadas. Las listas estarán ordenadas o bien Alfabéticamente o bien por cantidad de ocurrencias y luego alfabéticamente.-<br />Este caso es interesante si lo miramos más abstractamente. Lo que hace falta es un enumerador, que nos permita barrer la colección. Estos enumeradores tienen un método llamado MoveNext() y se conocen como genéricos, una de las funcionalidades de lenguajes como C#.<br />Tenemos para nuestra colección (que es un Diccionario: par/valor) un enumerador especifico denominado: IDictionaryEnumerator<br /><br />Para el caso de la enumeración de las palabras ordenadas alfabéticamente:<br /><br />// Retorna un enumerador para las palabras ordenadas alfabeticamente<br />public IDictionaryEnumerator GetPalabrasAlfabeticamenteEnumerator() {<br />return (IDictionaryEnumerator) ctdorDePalabras.GetEnumerator();<br />}<br />Observamos que la posibilidad de obtener un enumerador de una SortedList() esta a través del método GetEnumerator() (que es un IEnumerator).-<br />Y para el caso de la enumeración de las palabras ordenadas por ocurrencia y alfabéticamente:<br />public IDictionaryEnumerator GetPalabrasPorOccurrenciaEnumerator() {<br />…<br />}<br /></p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWrlq5YwwhwryTMOBMRaeAkBuVnuNS3RjikDOYmBdptCDFbeBiYUx0AG33LlHpspREDPQM-UiEHFyLvu59N3rO_5-1xWcIE5ltmlp9CYZyMmxesdWiR2Haqn78z5WOBvF9XODsmgztSw4/s1600/SortedList.jpg"></a><br /><div></div>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-79574634240968858022010-06-04T19:10:00.000-07:002010-06-04T19:18:38.544-07:00Programacion Reflexiva . PARTE III<a name="_Toc176770149"></a><a name="_Toc160022674"><strong>Algo más al respecto</strong></a><br /><br /><a href="http://msdn2.microsoft.com/en-us/library/hk5f40ct.aspx">Los</a> assemblies contienen módulos, los módulos contienen tipos y los tipos contienen funciones miembro o métodos.<br />-<br />Lo que Reflection provee son objetos que encapsulan a estas unidades (assemblies, módulos y tipos) de modo de crear dinámicamente una instancia de un tipo, ligar ese tipo a un objeto existente u obtener el tipo de un objeto existente.-<br /><br />De este modo podemos invocar los métodos del tipo y/o acceder a sus campos y propiedades. El uso típico de reflection debería seguir estas reglas:<br /><br />1. Usar la clase <a href="http://msdn2.microsoft.com/en-us/library/system.reflection.assembly.aspx">Assembly</a> para definir y cargar assemblies, cargar los módulos que el assembly contiene y que se encuentran en el Manifiesto, ubicar el tipo del assembly en si y crear una instancia del mismo.-<br /><br />Esto lo podemos hacer con:<br /><br /><strong>Assembly a = Assembly.LoadFrom(args[0]);<br /></strong>O<br /><strong>Assembly a = Assembly.GetExecutingAssembly();</strong><br /><br />El primer modo es genérico y solo requiere que se indique el assembly. (El paso completo del mismo será obligatorio si no se encuentra en la GAC). El segundo método está restringido a el trabajo con clases que se encuentran en el assembly actual.-<br /><br />2. Usar el método CreateInstance() para instanciar un objeto de un tipo dado:<br /><br /><strong><span style="font-size:85%;">Object o = assem.CreateInstance("Ejemplo2", false,<br />BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null);</span></strong><br /><br />· Alternativamente observemos que esto puede hacerse así:<br /><br /><strong><span style="font-size:85%;">MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");<br />Object ret = m.Invoke(o, new Object[] { 42 });<br /></span></strong><br />El método GetType retorna un objeto de la clase MethodInfo.<br />Observemos que igual que en el caso anterior, el nombre de la clase y el de su metodo, SON LITERALES lo que indica que pdrian ser cargados en tiempo de ejecucion en variables string y la llamada a Assembly.GetType o a Assembly.CreateInstance se podria hacer con datos dinamicos.<br />Desde ya que esta es la funcion ultima de Reflection.-<br />Observe de todos modos que debe conocer “algo” del tipo o del metodo de modo de invocar correctamente a los constructores o pasar parametros adecuados a los metodos.-<br /><br /><a name="_Toc176770150"></a><a name="_Toc160022675"><strong>EJEMPLO II</strong></a><br /><br />En este ejemplo haremos una variante que nos llevara a un caso más parecido al que planteamos al principio de esta y que mostramos con un ejemplo en lenguaje C.-<br />Construiremos 3 proyectos, ambos en la misma solucion solo a los efectos de la simplicidad.<br />Uno, al que llamaremos biblioteca1, correspondera al armado de una biblioteca donde estan las clases de las que crearemos objetos a los que a accederemos.-<br />El segundo, al que llamaremos pruebabiblioteca, sera una aplicacin intermedia de ayuda. Esto no es necesario para el proyecto final que es una aplicación que usando reflection hara uso de los metodos de la biblioteca. Pero es una biena idea probar la biblioteca SEPARADAMENTE antes de darle un uso generico. Es por eso que colocamos este proyecto dentro del ejemplo.-<br />El tercero, que es el que nos importa, sera la aplicación que a traves de Reflection accede a estos objetos y sus metodos en modo dinamico.-<br /><br /><a name="_Toc176770151"><strong>El proyecto biblioteca1</strong></a><br /><br />El primer proyecto sera del tipo Class Library y en el colocaremos una clase con dos metodos.-<br />Luego esta sera nuestra biblioteca armada como Assembly.-<br />Vamos con el primer proyecto que consiste en armar la biblioteca de la clase que expondra funcionalidad a ser utilizada por el segundo proyecto:<br />Este es un proyecto Class Library de modo de armar una biblioteca con una clase que exporte sus metodos.-<br /><br />El codigo que escribiremos para crear tal clase es el que se muestra a continuacion:<br /><br />using System;<br />using System.Collections.Generic;<br />using System.Text;<br /><br />namespace biblioteca1<br />{<br />public class UnaClase<br />{<br />public static Boolean SinNumeros(string dato)<br />{<br />char []numeros = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };<br />if (dato.LastIndexOfAny(numeros) == -1)<br />return (true);<br />else<br />return (false);<br />}<br /><br />public static Boolean SinÑuflos(string dato)<br />{<br />char []ñuflos = new char[] { '@', '^', '`', '¨', '~' };<br />if (dato.LastIndexOfAny(ñuflos) == -1)<br />return (true);<br />else<br />return (false);<br />}<br /><br />}<br />}<br /><br /><br />Ahora vamos a armar la biblioteca (biblioteca1) como una dll que expondrá la clase UnaClase y sus métodos públicos.-<br />Esto generara el archivo biblioteca1.dll .-<br />Revise en la pantalla de salida donde queda generada:<br /><br /><a name="_Toc176770152"><strong>El proyecto PruebaBiblioteca</strong></a><br /><br />Ahora vamos a construir el segundo proyecto<br /><br />Vamos a hacer una aplicación de consola que utilice la biblioteca creada en el proyecto anterior.<br />Lo hara del modo habitual, es decir sin utilizacion de reflection.<br />EL codigo C# de este proyecto esta en un solo modulo al que llamaremos Program y es el que se ve a continuacion:<br /><br /><strong><span style="font-size:85%;">using System;<br />using System.Collections.Generic;<br />using System.Text;<br />using biblioteca1;<br /><br />namespace PruebaBiblioteca<br />{<br />class Program<br />{<br />static void Main(string[] args)<br />{<br />string dato = "ABCDE";<br />if (biblioteca1.UnaClase.SinNumeros(dato) == true)<br />Console.WriteLine("{0}: No tiene numeros");<br />else<br />Console.WriteLine("{0}: Tiene numeros");<br /><br />dato = "AB1C2DE";<br />if (biblioteca1.UnaClase.SinNumeros(dato) == true)<br />Console.WriteLine("{0}: No tiene numeros");<br />else<br />Console.WriteLine("{0}: Tiene numeros");<br /><br />dato = "A~CDE";<br /><br />if (biblioteca1.UnaClase.SinÑuflos(dato) == true)<br />Console.WriteLine("{0}: No tiene Ñuflos");<br />else<br />Console.WriteLine("{0}: Tiene Ñuflos");<br /><br />}<br />}<br />}</span></strong>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-78708810215615461902010-06-04T17:04:00.000-07:002010-06-04T19:18:55.980-07:00Programacion Reflexiva . PARTE II<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCxtdPJ8qanYILb3SHVfkcwnS1SQ2KErvrGuH5kSNR9A_93RZ60vdhTVYVi_aLicI7HS3hO8EaDA2gCNwWofRmGifzKXc-C8dghF3xHoUNSsx8L8yd5NQwMujMJc1BKWKYglJIZQHaRAE/s1600/prI.png"></a><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKqS3vq3M0zpnHK_kIzjN4J_2YTYe8NfW_7njhYRiDqep-TeemRTeKdARjeMktxYe4pBM3OMwNx7C_TuqUF3OZyvIdTLB_fDSBG3q0kb2WvfZ4opC9-N2ooDVkN-aBxt9L7-OE5ob4ivo/s1600/prII.png"></a><span style="font-size:180%;">El enfoque en C#</span><br />El cargador del lenguaje común administra lo que se denominan DOMINIO de APLICACIONES. El lenguaje común es el CONTENEDOR que aísla al programa del SO. Cualquier aplicación desarrollada en .NET no se comunicara directamente con APIs de WIN32, tal como lo hacíamos anteriormente sino a través de funciones, servicios, etc. del contenedor.- EL DOMINIO de la APLICACIÓN es el contorno o los limites en los que trabajan aquellos objetos que pertenecen al mismo alcance de aplicación.- La administración de este cargador incluye la carga de cada assembly en el dominio de aplicación adecuado y controla la disposición y arreglo en memoria del tipo de jerarquía en cada assembly.-<br />Veamos unos ejemplos.-<br /><br /><strong>Ejemplo I</strong>:<br />En este caso haremos un proyecto que contendra las clases que queremos acceder a traves de Reflection.- Es por eso que utilizamos el metodo estatico: Assembly.GetExecutingAssembly(); para poder tener un objeto de la clase Assembly. Este es el modo de hacerlo cuando lo que necesitamos es un objeto de una clase que esta dentro del codigo actualmente en ejecucion.- Obtenemos un objeto de la clase Assembly de este modo : Assembly assem = new Assembly()) Este el objeto creado nos permitira, por ejemplo, instanciar objetos de las clases contenidas en el assembly.- Para eso el primer paso es:<br /><br /><br /><strong>¿Como acceder a una clase del assembly?</strong><br /><br />El objeto de la clase Assembly tiene un metodo llamado CreateInstance().<br />Este método admite como parámetro el nombre de una clase así como los parámetros que necesitase su constructor.<br />Este método es uno de los métodos capitales de la programación reflexiva ya que nos permite a través de un texto que representa el nombre de la clase, obtener un objeto que es una instancia de la misma.-<br />El codigo siguiente muestra la utilizacion del metodo<br /><br /><span style="font-size:85%;"><strong>CreateInstance(): </strong></span><br /><span style="font-size:85%;"></span><br /><span style="font-size:85%;">// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene // El constructor de Ejemplo2 necesita un parametro que es un entero //</span><br /><span style="font-size:85%;"><strong></strong></span><br /><span style="font-size:85%;"><strong>Object o = assem.CreateInstance("Ejemplo2", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null);</strong> </span><br /><br />Observe que se accede a una clase y se instancia un objeto de la misma a traves de un parametro que es un texto ("Ejemplo2").-<br />Observe tambien que uno de los parametros de CreateInstance() es un array de Object al que se le envian los parametros QUE EL CONSTRUCTOR de la clase necesita.<br />Esto es: No es suficiente con conocer el nombre de clase en el assembly sino que es preciso conocer algo mas de ella.<br />Esto es similar a lo que nos sucede en el programa C que vimos al inicio en el que debemos conocer algo del PROTOTIPO de la funcion para hacer una llamda exitosa.-<br /><br /><strong>¿Como acceder a un metodo de la clase?</strong><br /><br />Ahora bien, tenemos un objeto O que es una instancia de una clase del assembly. ¿Como hacemos ahora para acceder a un metodo de dicha clase?<br />El handler al assembly (assem) tiene un metodo llamado GetType que obtiene información sobre el tipo exacto que se produce en tiempo de ejecucion para el objeto corriente.-<br />Es decir GetType retorna un tipo (Type). La clase Type es la base de reflection para acceder a la metada del objeto. Type es una interfaz que tiene distintas implementaciones. La que aquí no sinteresa, tiene un metodo llamado GetMethod() que, tomando como parametro el nombre del metodo, nos trae información del mismo. Asi:<br /><br /><strong><span style="font-size:85%;">MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");</span></strong><br /><br />Obtenida la información sobre el metodo, se lo puede invocar a traves del metodo Invoke de MethodInfo .<br />Igual que en el caso anterior, si bien es posible obtener acceso al metodo a traves de un literal (en este caso el nombre del metodo es : MetodoDeEjemplo ), el uso posterior del metodo requiere conocer cuales son los parametros adecuados.<br /><br /><strong><span style="font-size:85%;">Object ret = m.Invoke(o, new Object[] { 42 });</span></strong><br /><br />En este caso el entero 42 se corresponde al tipo de datos que corresponde al Metodo, MetodoDeEjemplo EL retorno que produce Invoke es un Object.<br /><br />EL uso posterior del mismo sera parte de la logica de negocios del programa.-<br /><br />Arme un proyecto de consola simple y coloque el código indicado en un modulo cs (C#)<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB6jMliJHg_p_lsatMQhEOe1ONLXqR1IVSFjHcqLz2ZOds6NUBIToswiKYPtj9R9Qr58BmVkc7dD9fJvRdMNrMII7VMg_pBtWtFRgOYRCFaVGSyCtZvC7TZWfEW6txNA9Ghq6ZxTdAw60/s1600/prII.jpg"><img id="BLOGGER_PHOTO_ID_5479074449411524962" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 320px; CURSOR: hand; HEIGHT: 240px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB6jMliJHg_p_lsatMQhEOe1ONLXqR1IVSFjHcqLz2ZOds6NUBIToswiKYPtj9R9Qr58BmVkc7dD9fJvRdMNrMII7VMg_pBtWtFRgOYRCFaVGSyCtZvC7TZWfEW6txNA9Ghq6ZxTdAw60/s320/prII.jpg" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Y pruebe este codigo:<br /><br /><span style="font-size:85%;"><strong>using System;<br />using System.Collections.Generic;<br />using System.Text;<br />using System.Reflection;<br />using System.Security.Permissions;<br />using System.Configuration;<br /><br /><br /><br />class Ejemplo2<br />{<br />private int factor;<br /></strong></span><br /><span style="font-size:85%;"><strong>public Ejemplo2(int f)<br />{<br />factor = f;<br />}<br /><br />public int MetodoDeEjemplo(int x)<br />{<br />Console.WriteLine("\nEjemplo2.MetodoDeEjemplo({0}) ejecutado.", x);<br />return x * factor;<br />}<br /><br />public string OtroMetodo(string a)<br />{<br /><br />StringBuilder st = new StringBuilder("A este dato le concateno: ");<br />Console.WriteLine("\nEjemplo2.OtroMetodo({0}) ejecutado.", a);<br />st.Append(a);<br />return st.ToString();<br />}<br /><br /><br />}<br /><br />public class ejecuta<br />{<br /><br />public static void Main()<br />{<br /><br />Assembly assem = Assembly.GetExecutingAssembly();<br /><br />Console.WriteLine("Nombre completo del Assembly:");<br />Console.WriteLine(assem.FullName);<br /><br />//<br />AssemblyName assemName = assem.GetName();<br />Console.WriteLine("\nName: {0}", assemName.Name);<br />Console.WriteLine("Version: {0}.{1}",<br />assemName.Version.Major, assemName.Version.Minor);<br /><br />Console.WriteLine("\nAssembly CodeBase:");<br />Console.WriteLine(assem.CodeBase);<br /><br /></strong>// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene<br />//El constructor de Ejemplo2 necesita un parametro que es un entero<br />//<br /><strong>Object o = assem.CreateInstance("Ejemplo2", false,<br />BindingFlags.ExactBinding,<br />null, new Object[] { 2 }, null, null);<br /><br /></strong>// Ahora apuntamos a un metodo del objeto:<br /><br /><strong>MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");<br />Object ret = m.Invoke(o, new Object[] { 42 });<br />Console.WriteLine("MetodoDeEjemplo retorno: {0}.", ret);<br /><br />MethodInfo m2 = assem.GetType("Ejemplo2").GetMethod("OtroMetodo");<br />ret = m2.Invoke(o, new Object[] { "Este Texto" });<br />Console.WriteLine("OtroMetodo retorno: {0}.", ret);<br /><br />Console.WriteLine("\nPunto de entrada del Assembly:");<br />Console.WriteLine(assem.EntryPoint);<br />}<br />}<br /></strong></span><br />Ejecute el codigo y vera que nos muestra lo siguiente:<br /><br />El nombre del assembly<br />El metodo que hemos ejecutado y el valor que retorna el mismo<br />El punto de entrada del assemblyEduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-60314884780365755972010-06-04T16:45:00.000-07:002010-06-04T19:19:11.006-07:00La programacion Reflexiva-PARTE I<a name="_Toc176770143"><span style="font-size:180%;">Reflection</span></a><br /><br />Para la ejecucion de una aplicación .NET debemos tener presente el concepto de CONTENEDORES. Este es un concepto que se ha popularizado los ultimos años a traves de Java y difiere de los habituales run-times en que no es un agregado que lleva el ejecutable o un conjunto de bibliotecas que resuelven aspectos especificos (como graficos), SINO QUE ES UNA MAQUINA VIRTUAL dentro de la cual corre la aplicación.-<br />Es decir esta cascara es la que separa a la aplicación del Sistema operativo.-<br />Sus ventajas en el mundo Java son obvias en tanto estos contenedores aislan al programador de especificidades de tal o cual sistema operativo.-<br />No nos resultan tan obvias en el mundo Microsoft donde existe UN SOLO sistema operativo.-<br />Sin embargo hay otras decisiones que seguramente habrán pesado en la decisión de Microsoft de hacer un esquema de contenedores.-<br />El primero es que este esquema permite que exista un nivel de compilación que no es la generación del ejecutable mismo, sino de un lenguaje intermedio (MSIL para Microsoft, Bytecodes para Java y… P-CODE para quienes tuvimos oportunidad de trabajar profesionalmente con el maravilloso Pascal ¡!).-<br />El segundo es que varios lenguajes (al menos Visual Basic, C# y C++ en modo manejado) pueden trabajar sobre esta maquina virtual y compartir aquellos servicios, bibliotecas y assemblies que la maquina virtual necesita. Esto es un enorme avance desde el punto de vista de cómo cada lenguaje expone funcionalidades comunes a los programadores.-<br />Tambien aca podemos decir que esto existía, para determinados servicios, en los sistemas operativos propietarios de Digital e IBM.-<br />Sobre todo en los del primero, su sistema operativo VMS (hoy propiedad de Hewlett Packard) presentaba para la familia de lenguajes (Fortran, C, Cobol y Basic) idénticos nombres de rutinas para todo el sistema de I/O y de archivos ISAM.-<br />Solo que en estos casos un runtime que se adjuntaba al programa compilado era el encargado de proveer esta funcionalidad comun. Esto por supuesto duplicaba el codigo en cierto punto, aunque los servicios que utilizaba el runtime estaban en el kernel del SO por lo que no era tan problemático.-<br /><a name="_Toc176770144"></a><a name="_Toc160022671">¿Como funciona esto y para que sirve realmente?</a><br />Vamos a hacer un par de aplicaciones que nos muestren como funciona esto.<br />Antes de avanzar nos gustaría que repasemos como, en un lenguaje como el C, resolvemos un problema común:<br />Queremos invocar un método, que esta en una biblioteca CUYO ENLACE no se produce cuando compilamos, sino en tiempo de ejecución.-<br />Esto da a nuestros programas otra versatilidad. Es decir nuestro programa es capaz de:<br />Cargar una biblioteca a traves de su nombre LITERAL. Es decir un string en tiempo de ejecucion (por ejemplo leido de un archivo de configuración) dira cual es la biblioteca a a cargar)<br />Colocar un apuntador a una funcion de dicha biblioteca (definible tambien como un string)<br />Hay alguna habilidad que debe tener el SO en el que trabajamos y es la de aceptar bibliotecas compartidas. En Windows estas tienen la extension .DLL y en UNIX la extension .SO<br />Es decir la biblioteca que invocaremos desde nuestra aplicación sera del tipo compartida (Shared) y no del tipo estatica (STATIC).-<br />El ejemplo lo haremos para UNIX solo para ver alguna pequeña diferencia de cómo lo hariamos en Windows.-<br />El programa que haremos sabra cargar una biblioteca por nombre. En nuestro caso los nombres son lib1.so y lib2.so. Estos nombres son totalmente arbitrarios y podrian ser cualquier otro valido para el Sistema operativo.-<br />El programa cargara alguna de estas 2 bibliotecas y llamara la funcion saludo().<br />Esta funcion existe en ambas bibliotecas y el programa es capaz de trabajar con esta redefinicion (override) ya que dependera de la biblioteca que cargue lo que determinara cual es la tarea que termine realizando.-<br />Este es el codigo de una biblioteca escrito en ANSI C:<br /><br /><span style="font-size:85%;"><strong>#include "stdio.h";<stdio><br />#include "dlfcn.h";/* bibliotecas de manejo dinamico de funciones:<br />dlopen(), dlclose(), dlsym() ... */<br /><br />/* Explicamos como usar el programa. */<br />void usage(int argc, char* argv[])<br />{<br />fprintf(stderr, "Usar asi: %s [12] a los efectos de llamar a la lib1 o a la lib2 \n", argv[0]);<br />exit(1);<br />}<br /><br />int main(int argc, char* argv[])<br />{<br />int lib_num;</strong> /* Que biblioteca usar ? */<br /><strong>char biblioteca[100];</strong> /* nombre del archivo de la biblioteca */<br /><strong>void* lib_handle;</strong> /* manejador para la biblioteca compartida cargada*/<br /><strong>void (*fn_de_la_biblioteca)();</strong> /* puntero a UNA FUNCION de la biblioteca*/<br /><strong>const char* error;</strong> /* por si hay errores... */<br /><br /><strong>/* necesito un argumento */<br />if (argc != 2)<br />usage(argc, argv);</strong> /* Chau!! */<br /><br /><strong>/* Esta es la biblioteca a cargar. */<br />lib_num = atoi(argv[1]); /* */<br /><br />if (lib_num < 1 lib_num > 2)<br />usage(argc, argv); /* Chau !! */<br /><br /></strong>/* ahora armo el nombre de la biblioteca concatenando la palabra "lib" con el numero 1 o 2<br />para obtener lib1.so o lib2.so */<br /><strong>sprintf(biblioteca, "lib%d.so", lib_num);<br /><br /></strong>/* carga la biblioteca que desea (lib1.so o lib2.so) */<br /><strong>lib_handle = dlopen(biblioteca, RTLD_LAZY); </strong></span><br /><span style="font-size:85%;"><br /><br /><strong>if (!lib_handle) </strong><br /><strong>{<br />fprintf(stderr, "Error: %s\n", dlerror());<br />exit(1);<br />}<br /><br /></strong>/* cargar la funcion saludo QUE ESTA EN CUALQUIERA<br />DE LAS DOS BIBLIOTECAS !*/<strong><br />fn_de_la_biblioteca = dlsym(lib_handle, "saludo");<br /><br />error = dlerror();<br />if (error) {<br />fprintf(stderr, "Error: %s\n", error);<br />exit(1);<br />}<br /><br /></strong>/* Llamar a la funcion. */<br /><strong>(*fn_de_la_biblioteca)();<br /><br /></strong>/* liberar el recurso */<br /><strong>dlclose(lib_handle);<br /><br />return 0;<br />}<br /><br />Este modulo es LIB1.SO:<br /><br />#include <stdio>;<br /><br />/* Esta es la funcion de la biblioteca*/<br />void saludo()<br />{<br />printf("Que puedo decir que no sea HOLA MUNDO?\n");<br />}<br /><br />/* cleanup de la biblioteca */<br />void _fini()<br />{<br />printf("Limpiando la biblioteca 'lib2.so'\n");<br />}<br /><br />Este modulo es LIB2.SO:<br />#include <stdio.h>;<br /><br />/* funcion de inicializacion: OBLIGATORIO llamarla '_init'. */<br />void _init()<br />{<br />printf("Inicializando biblioteca 'lib1.so'\n");<br />}<br /><br />/* Esta es lo funcion que nos importa */<br />void saludo()<br />{<br />printf("HALOAA !!\n");<br />}<br /></strong></span><br />Como vemos este problema responde a un patron comun: La resolucion en tiempo de ejecucion de una funcionalidad determinada.-<br />Los lenguajes modernos como C# y Java resuelven esto con el paradigma denominado programacion reflexiva.<br />Como en muchos otros conceptos de estos lenguajes modernos, las ideas se generaron en Smalltalk y C++.-Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-27791162605011847952010-04-26T18:52:00.001-07:002010-04-29T18:25:08.603-07:00Algo sobre threads en C# - Parte III<div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNboJVIiGbqtVwek9NN0oj0yZtmmfHwvD48DON1JRgl4qg7QdCu04UoVyPosadiGZE43mDJ5EhgGCKdiRuVz5nGgM8DCbnpIeoqig_bf2RO4zawUI0ZUTAh0qI1Rr8khcVnZ6CDJBrssQ/s1600/thr1.jpg"></a><br /><br /><div><span style="font-size:large;color:red;"><strong><span style="font-size:x-large;">OBJETIVO</span> </strong></span><br /><br /><br />Veamos ahora un modelo de implementación de threads así como la implementación de dos patrones de desarrollo clásicos: Command y Strategy.-<br /><br />Para eso vamos a plantearnos un motor batch , es decir un proceso que sea capaz de disparar procesos batch (no interqactivos ) en diferentes hilos de ejecucion<br /><br /><br /><span style="font-size:large;color:blue;"><strong>Un motor de procesos batch</strong></span><br /><br />Un motor de procesos batch es un software que es capaz de ejecutar procesos batch de modo concurrente y controlado.-<br /><br />Lo que expondremos acá es un modelo simple del mismo del que después pueda derivarse un motor de uso profesional.-<br /><br />Lo importante del motor desde el punto de vista de la arquitectura es que se trata de una aplicación que es capaz de manejar múltiples hilos de ejecución, colocar en cada uno de esos hilos un proceso a ejecutar , lanzar dichos procesos , esperar su conclusión y reportar que el proceso finalizo.-<br /><br /><br />Lo importante del motor desde el punto de vista de la técnica de diseño es que cumple con un patrón de los enunciados por Gamma y otros (GoF [1]).<br />Este patrón se denomina Command (Comando).<br /><br />La idea de Comando como patrón de nuestro diseño es un objeto que tenga 3 estadios clásicos: Inicio, ejecución y cierre. Llamaremos a esos métodos como Inicio(), run() y CleanUp().-<br /><br />Caulquier implementacion que tengo estas 3 tareas sera apra nostros un comando.<br />Pensemos entonces en una estrcutura de programacion que nos permita sugerir esta plantilla antes de implementarla. Llamamos a esto Interfaz<br /><br />La Interfaz Comando<br /><br /><br /><br /><br /><strong><span style="font-size:x-small;">using System;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Collections.Generic;</span></strong><br /><strong><span style="font-size:x-small;">using System.Text;</span></strong><br /><strong><span style="font-size:x-small;">namespace ThreadPoolTest_5</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public interface Comando</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">void inicio();</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">void run();</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">void cleanup();</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><br /><span style="font-size:large;color:white;"><strong>Las clases que implementan la interfaz Comando</strong></span><br /><br /><br />Veamos ahora clases concretas de la Interfaz comando. Estas clases implementan los métodos declarados en la interfaz.-<br /><br />Daremos dos implementaciones una llamada miClase y la otra llamada miOtraClase.-<br /><br />No tienen nada de particular salvo que ambas implementan a la interfaz Comando.-<br /><br /><span style="color:blue;"><strong>La clase miClase</strong></span><br /><br />Esta primera funcion solo consumo tiempo de procesamiento<br /><br /><strong><span style="font-size:x-small;">using System;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Collections.Generic;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Text;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Threading;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">namespace ThreadPoolTest_5</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public class miClase : Comando</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">private string _nombre;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">private bool _terminado;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public string nombre</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">get { return _nombre; }</span></strong><br /><strong><span style="font-size:x-small;">set { _nombre = value; }</span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public bool terminado</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">get { return _terminado; }</span></strong><br /><strong><span style="font-size:x-small;">set { _terminado = value; }</span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public void inicio()</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">_terminado = false;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><br /><br /><br /><strong><span style="font-size:x-small;">public void run()</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">Console.WriteLine(this.GetType().ToString() + " :Procesando requerimiento '{0}'." +</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">" Hash: {1}", </span></strong><strong><span style="font-size:x-small;">(string)nombre, Thread.CurrentThread.GetHashCode());</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">// Simulacion de tiempo de procesamiento</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">int ticks = Environment.TickCount;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">//Trabajar mientras no hayan transcurrido los 2 segundos</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">while (Environment.TickCount - ticks < 2000) ;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">Console.WriteLine("Requerimiento '{0}' procesado",</span></strong><strong><span style="font-size:x-small;">(string)nombre);</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public void cleanup()</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">_terminado = true;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}// de clase</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}// de namespace</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="color:white;">La clase mi otraclase</span></strong><br /><br />Esta segunda funcion calcula el coseno de un angulo en radianes por el metodo de expansion:<br /><br /><strong><span style="font-size:x-small;">using System;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Collections.Generic;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Text;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">using System.Threading;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><br /><strong><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">namespace ThreadPoolTest_5</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">public class miOtraClase : Comando</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">private string _nombre;</span></strong><br /><strong><span style="font-size:x-small;">private bool _terminado;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public string nombre</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">get { return _nombre; }</span></strong><br /><strong><span style="font-size:x-small;">set { _nombre = value; }</span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public bool terminado</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">get { return _terminado; }</span></strong><br /><strong><span style="font-size:x-small;">set { _terminado = value; }</span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public void inicio()</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">_terminado = false;</span></strong><br /><strong><span style="font-size:x-small;">} </span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">public void run()</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">Console.WriteLine(this.GetType().ToString() +": Procesando requerimiento '{0}'." +</span></strong><strong><span style="font-size:x-small;">" Hash: {1}",</span></strong><br /><strong><span style="font-size:x-small;">(string)nombre, Thread.CurrentThread.GetHashCode());</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">//Calcular</span></strong><br /><strong><span style="font-size:x-small;">CalcularCosenos();</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">Console.WriteLine("Requerimiento '{0}' procesado", </span></strong><strong><span style="font-size:x-small;">(string)nombre);</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">}</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">private void CalcularCosenos()</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">const double EPSILON = 0.000000001;</span></strong><br /><strong><span style="font-size:x-small;">const double DESDE = 0.5346222;</span></strong><br /><strong><span style="font-size:x-small;">const double HASTA = 3.1415926;</span></strong><br /><strong><span style="font-size:x-small;">const double PASO = 0.000001999;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double lRadianes = DESDE;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double RadCuadrado;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double s;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double t;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double dFabsLRas;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">double dFabsProd;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">int k;</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">string Aux = "";</span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><br /><span style="font-size:x-small;"></span></strong><br /><strong><span style="font-size:x-small;">while (lRadianes < HASTA)</span></strong><br /><strong><span style="font-size:x-small;">{</span></strong><br /><strong><span style="font-size:x-small;">k = 0;</span></strong><br /><strong><span style="font-size:x-small;">t = 1;</span></strong><br /><strong><span style="font-size:x-small;">s = 1;</span></strong><br /><strong><span style="font-size:x-small;">RadCuadrado = lRadianes * lRadianes;</span></strong><br /><strong><span style="font-size:x-small;">dFabsLRas = Math.Abs(t);</span></strong><br /><strong><span style="font-size:x-small;">dFabsProd = (EPSILON * Math.Abs(s));</span></strong><br /><br /><strong><span style="font-size:x-small;">//Calculamos la expansion hasta que el termino enesimo no sea mayor a un EPSILON DADO</span></strong><br /><strong><span style="font-size:x-small;">while (dFabsLRas > dFabsProd)</span></strong><br /><span style="font-size:x-small;color:black;"><strong>{</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>k = k + 2;</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>t = (-1) * t * s * RadCuadrado/ (k * (k - 1));</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>// 1 - x^2/2! + x^4/4! - x^8/8! ...</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>s = s + t;</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>dFabsProd = (EPSILON * Math.Abs(s));</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>dFabsLRas = Math.Abs(t);</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>}</strong></span><br /><br /><strong><span style="font-size:x-small;color:black;"></span></strong><br /><span style="font-size:x-small;color:black;"><strong>Aux = lRadianes.ToString() + ":" + s.ToString();</strong></span><br /><strong><span style="font-size:x-small;">Console.WriteLine(Aux);</span></strong><br /><span style="font-size:x-small;"><strong></strong></span><span style="color:black;"></span><span style="font-size:x-small;color:black;"><strong>lRadianes += PASO;</strong></span><br /><br /><span style="font-size:x-small;color:black;"></span><br /><span style="font-size:x-small;color:black;">}</span><br /><br /><span style="font-size:x-small;color:black;"><strong>}</strong></span><br /><br /><span style="font-size:x-small;color:black;"><strong></strong></span><br /><span style="font-size:x-small;color:black;"><strong>public void cleanup()</strong></span><br /><span style="font-size:x-small;color:black;"><strong>{</strong></span><br /><br /><span style="font-size:x-small;color:black;"><strong></strong></span><br /><span style="font-size:x-small;color:black;"><strong>_terminado = true;</strong></span><br /><br /><span style="font-size:x-small;color:black;"><strong></strong></span><br /><span style="font-size:x-small;color:black;"><strong>}</strong></span><br /><br /><span style="font-size:x-small;color:black;"><strong></strong></span><br /><span style="font-size:x-small;color:black;"><strong>}</strong></span><br /><br /><span style="font-size:x-small;color:black;"><strong></strong></span><br /><span style="font-size:x-small;color:black;"><strong>}</strong></span><br /><br /><br /><span style="font-size:large;color:blue;"><strong>El motor batch de tareas asíncronas</strong></span><br /><br /><br />Ahora vamos a implementar el motor.-<br /><br />El motor de tareas asíncronas representa una implementación de un modelo de procesamiento de un software capaz de disparar OTRAS tareas según una configuración de tiempos.-<br /><br />En el ejemplo estamos utilizando 4 conceptos sobre los que el motor esta diseñado:<br /><br />1- Para que el motor deba ejecutar un proceso en hilos (threads) múltiples usaremos un namespace llamado System.Threading en el que encontramos una clase llamada WaitCallback que es la implementación de un prototipo de función CallBack [2].-<br /><br />2- La clase WaitCallback, necesita en su constructor un método que cumpla con este prototipo :<br /><br /><strong><span style="font-size:x-small;">private static void MiFuncion(object miObjeto);</span></strong><br /><br />De modo que nosotros creamos un método dentro de nuestra clase de implementación del motor que pueda cumplir con este prototipo.-<br /><br />3- La clase ThreadPool, con métodos estáticos públicos es la que nos permitirá levantar cada uno de los procesos que el motor batch dispara. ThreadPool nos permite definir la cantidad de threads que se abrirán en la sesión así como encolar los procesos que disparamos de modo de ejecutarlos secuencialmente.-<br /><br />4- EL motor tiene un método llamado Trabaja() que es el que ejecuta la parte central de la tarea. Ahora bien : ¿ Que necesita Trabaja() para hacer su tarea ?.<br /><br /><br />Necesita una lista de objetos. De alli que Trabaja() tiene como parámetro un contenedor genérico <list>de objetos a procesar.-<br /><br /><strong><span style="font-size:85%;">using System;<br />using System.Collections.Generic;<br />using System.Text;<br />using System.Threading;<br /><br /><br />namespace ThreadPoolTest_5<br />{<br />class MotorBatch<br />{<br /><br />public static void trabaja(List <> cm)<br />{<br />//EL motor tiene su funcion de disparo y arma un<br />// handler a ella<br />WaitCallback callBack;<br />callBack = new WaitCallback(FuncionAEjecutar);<br /><br />//El motor ajusta la cantidad de threads por procesador<br />int minWorker, minIOC;<br />ThreadPool.GetMinThreads(out minWorker, out minIOC);<br />// 4 threads asincronicos como minimo, por procesador<br />ThreadPool.SetMinThreads(4, minIOC);<br /><br />//El motor lanza las tareas<br />foreach(object com in cm)<br />{<br />ThreadPool.QueueUserWorkItem(callBack, com);<br />}<br /><br />//El motor sincroniza el pool de threads<br />//Hasta terminar<br />Console.ReadLine();<br />}<br /><br />private static void FuncionAEjecutar(object mc)<br />{<br />Comando xco = (Comando)mc;<br />xco.inicio();<br />xco.run();<br />xco.cleanup();<br />}<br /><br />}//clase<br /><br />}//namespace</span></strong><br /><br /><br /><br /><a name="_Toc170628659"><span style="font-size:130%;color:#000099;"><strong>Un programa que utiliza el motor batch</strong></span></a><span style="color:#000099;"><br /></span><br />Corresponde ahora que hagamos un programa que utiliza el motor batch para dispara procesos. Lo que haremos será que el motor dispare las implementaciones de Comando que hicimos con miClase y miOtraClase.-<br />Observemos que es lo que nuestro programa hace ahora:<br />Siendo que el motor necesita que a su método publico y estático Trabaja() se le pase como parámetro un genérico de tipo <list>con objetos, lo primero que hace la aplicación que llamara al motor es generar una lista de dicho tipo.<br />Podemos ir viendo ya que esta generación es una tarea que debería estar controlada en el sentido que no podemos colocar cualquier tipo de objetos en esa lista sino solamente aquellos que deriven de Comando. Ese punto lo revisaremos en las mejoras que haremos al motor batch.-<br /><br /><br /><br />using System;<br />using System.Threading;<br />using System.Collections.Generic;<br /><br />namespace ThreadPoolTest_5<br />{<br /><br />//<br />class MainApp<br />{<br />static void Main()<br />{<br />//Alguien carga los comandos en una lista y el motor<br />//la invoca<br />List <> cm = ListaDeComandos();<br /><br />MotorBatch.trabaja(cm);<br /><br />}<br /><br />static public List<anobject> ListaDeComandos()<br />{<br />miClase mc;<br />miOtraClase moc;<br />List<> comandos = new List<> <anobject>();<br /><br />for (int i = 0; i <> </div><br /><div>{ </div><br /><div>if ((i % 2) != 0) </div><br /><div>{</div><br /><div>mc = new miClase(); </div><br /><div>mc.nombre = "Hilo nro: " + i; comandos.Add(mc); </div><br /><div>} </div><br /><div>else </div><br /><div>{ </div><br /><div>moc = new miOtraClase(); </div><br /><div>moc.nombre = "Hilo nro: " + i; </div><br /><div>comandos.Add(moc); </div><br /><div>} </div><br /><div>}//for..</div><br /><div></div><br /><div>return comandos; </div><br /><div>}// </div><br /><div>} </div><br /><div>}</div><br /><div><br /></div><div></div><div><br /> </div></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAts2WE2eZCq-nR9QVM_Zz2xif7NPm6IGkpkX7YTF0rkgKnFgR-du-DT0lUt7xzmPPo5M0SulZivajQPPpYHsxC40Bto4CAQTIdqgFZ7TCJC_pOLvSeyOg1F8gipdTbeNuj6qPj8HHIr4/s1600/thr1.jpg"><img id="BLOGGER_PHOTO_ID_5465733801003033538" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 339px; CURSOR: hand; HEIGHT: 220px" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAts2WE2eZCq-nR9QVM_Zz2xif7NPm6IGkpkX7YTF0rkgKnFgR-du-DT0lUt7xzmPPo5M0SulZivajQPPpYHsxC40Bto4CAQTIdqgFZ7TCJC_pOLvSeyOg1F8gipdTbeNuj6qPj8HHIr4/s320/thr1.jpg" border="0" /></a><br /></div><br /><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> </div><div> Vemos en esta sencillo ejemplo las ideas basixas del motor batch y su rapida implementaciom</div><div> Dejamos para una IV parte de esta serie una version con mejoras en el diseño del motor</div><div> </div><div>**************************************<a name="_Toc170628660"> </a></div><div>[1] GoF es el acrónimo de “Gang of Four” o sea “La banda de los cuatro”. El nombre es una broma que liga la denominación de los 4 autores del libro Pattern Designs (Gamma, Helms, Jhonson y Vlissides)con la denominación de un grupo político del poder chino posterior a la muerte de Mao Tse Tung al que se lo acuso de traición por sus posturas radicalizadas durante la revolución cultural .-</div>Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com1tag:blogger.com,1999:blog-4330427453885266705.post-71753890225535900742010-04-24T13:37:00.000-07:002010-04-24T14:15:02.391-07:00Algo sobre threads en C# - Nota 2<span style="color: red; font-size: x-large;">POOL DE THREADS</span><br />
<br />
<br />
<span style="color: blue; font-size: large;">Un modelo hibrido toma aspectos comunes de cada enfoque</span><br />
<br />
Para evitar este tipo de problemas la solución adoptada en la industria es el uso de brokers (distribuidores de un pool de recursos).-<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM9j071l0XrMphbkwG2htKGDuYenj1jfO5tvNo8qeFpO2w1RajBT2WTDnQCCtbY7-TLj8FmpYU9vESjrY6V66yPZM0sZaG9hePKIhm3yOuV2PZszMRLneraB3J1TIK4x5W9qAeS5DjoPA/s1600/thr1.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM9j071l0XrMphbkwG2htKGDuYenj1jfO5tvNo8qeFpO2w1RajBT2WTDnQCCtbY7-TLj8FmpYU9vESjrY6V66yPZM0sZaG9hePKIhm3yOuV2PZszMRLneraB3J1TIK4x5W9qAeS5DjoPA/s320/thr1.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><br />
<br />
En esta aproximación al problema, existe un administrador de los pedidos encolados, que se encarga de derivarla al primer thread libre.- <br />
<br />
<br />
Por supuesto que definir la “habilidad” de este administrador para actuar como un broker no es sencillo.-<br />
<br />
Un buen administrador del pool, no debe limitarse a habilitar N threads, ya que quizás N sea un numero conservador (y por ende el procesador será subutilizado) o N es un numero ambicioso y podemos llegar al problema de aumento geométrico de la carga descrito al inicio de este capitulo.-<br />
<br />
El broker debe descubrir EN TIEMPO REAL, si existe o no potencia de procesamiento ociosa para decidir si habilita un nuevo thread o espera que alguno se libere.-<br />
<br />
<span style="color: red; font-size: large;">La solución en C# con pool de threads</span><br />
<br />
<br />
<br />
Siendo este un problema común, dentro del Framework de .NET tenemos un namespace que nos brinda un administrador de un pool de threads.-<br />
El namespace se denomina System.Threading y la clase se llama ThreadPool.-<br />
Dentro de esta clase tenemos todos métodos estáticos, lo que permite utilizarlos con llamadas globales.-<br />
Veamos un programa que presenta una aproximación al problema con las herramientas que nos brinda C#.-<br />
<br />
<strong><span style="font-size: xx-small;">using System;</span></strong><br />
<strong><span style="font-size: xx-small;"></span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">using System.Threading;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">//En este ejemplo utilizamos una técnica de threading en la que enviamos</span></strong><br />
<strong><span style="font-size: xx-small;">// como parámetro del constructor (WaitCallback) un METODO de la clase</span></strong><br />
<strong><span style="font-size: xx-small;">// es decir a diferencia de como se puede implementar este tipo de técnicas en Java</span></strong><br />
<strong><span style="font-size: xx-small;">// (que se pasan objetos) acá mandamos el nombre del método (función) que se debe ejecutar</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">namespace ThreadPoolTest</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">class MainApp</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">static void Main()</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">WaitCallback callBack;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">callBack = new WaitCallback(FuncionAEjecutar);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">ThreadPool.QueueUserWorkItem(callBack,"Hilo 1");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">ThreadPool.QueueUserWorkItem(callBack,"Hilo 2");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">ThreadPool.QueueUserWorkItem(callBack,"Hilo 3"); </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.ReadLine();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">static void FuncionAEjecutar(object state)</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Procesando requerimiento '{0}'." + </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> " El thread esta dentro del pool ?: {1}, Hash: {2}",</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> (string)state, Thread.CurrentThread.IsThreadPoolThread, </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.CurrentThread.GetHashCode());</span></strong><br />
<br />
<strong><span style="font-size: xx-small;"> // Simulacion de tiempo de procesamiento</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.Sleep(2000);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Requerimiento '{0}' procesado",</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> (string)state);</span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGSP7fIY4GBXN_lT-hAPE60NbH91n8MSfNLwAGC-Z4lA7sAqjtj_h9xd3DH8jXdgxpwBMJrzXVyPaFz_MTeqsBwTH1e1cjdwJf38LGR5vK1Dw5p7Xpz5r3ikUnFO-VkITkJTuckUDfhPI/s1600/thr2.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="118" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGSP7fIY4GBXN_lT-hAPE60NbH91n8MSfNLwAGC-Z4lA7sAqjtj_h9xd3DH8jXdgxpwBMJrzXVyPaFz_MTeqsBwTH1e1cjdwJf38LGR5vK1Dw5p7Xpz5r3ikUnFO-VkITkJTuckUDfhPI/s400/thr2.jpg" tt="true" width="400" /></a></div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Este es un ejemplo interesante que nos muestra cuando puede ser útil en un proceso batch el uso de hilos múltiples.-<br />
<br />
<br />
Observe que cada llamada a la función se ejecuto en un thread independiente, mientras en otro thread se ejecutaba otra llamada a la función.-<br />
<br />
Esto puede parecerse a un programa de comunicaciones que puede atender llamadas multiples.-<br />
<br />
Frente a cada llamada levanta un thread, pero cada thread llama a la misma funcion de atencion.-<br />
<br />
Lo que hicimos en la función llamada FuncionAEjecutar() fue hacerle perder tiempo (Thread.Sleep) para poder ver en la consola esta “simultaneidad” de procesamiento.-<br />
<br />
Observe, como comentamos líneas arriba, que los implementadores de la clase han decidido que todos los métodos sean públicos y estáticos.-<br />
<br />
El objetivo es hacer de esto un Singleton, es decir que solo exista una instancia de la clase para todo el proceso o sesión.-<br />
<br />
Si bien esto podría haberse hecho con un enfoque mas orientado a objetos (constructor privado, interfaz para implementar las funciones a llamar, polimorfismo para las llamadas de las funciones a colocar en el thread), los implementadores entendieron que no era el mejor camino, al menos en C#.-<br />
<br />
Esto nos habla de decisiones de diseño, algo que todos los ingenieros de software deben (o deberían) aprender.-<br />
<span style="font-family: inherit;"></span><br />
Hagamos una pequeña variante al ejemplo anterior para ver más claramente la ejecución en hilos separados.<br />
<br />
En este caso la función llamada en el primer thread termina antes que el disparo de todos los threads requeridos.-<br />
<br />
Pero esto no afecta para nada el enfoque del programa.-<br />
<br />
<strong><span style="font-size: xx-small;">using System;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">using System.Threading;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">//En este ejemplo utilizamos una tecnica de threading en la que enviamos</span></strong><br />
<strong><span style="font-size: xx-small;">// como parametro del constructor (WaitCallback) un METODO de la clase</span></strong><br />
<strong><span style="font-size: xx-small;">// es decir a diferencia de como se puede implementar este tipo de tecnicas en Java</span></strong><br />
<strong><span style="font-size: xx-small;">// (que se pasan objetos) aca mandamos el nombre del metodo (funcion) que se debe ejecutar</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">namespace ThreadPoolTest</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">class MainApp</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><span style="font-size: xx-small;">static void Main()</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<br />
<strong><span style="font-size: xx-small;">WaitCallback callBack;</span></strong><br />
<strong><span style="font-size: xx-small;">callBack = new WaitCallback(FuncionAEjecutar);</span></strong><br />
<strong><span style="font-size: xx-small;">string s;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">for (int i=0; i < 8; i++)</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> s = "Hilo nro: " + i;</span></strong><br />
<strong><span style="font-size: xx-small;"> ThreadPool.QueueUserWorkItem(callBack,s);</span></strong><br />
<strong><span style="font-size: xx-small;">} </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.ReadLine();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">static void FuncionAEjecutar(object state)</span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Procesando requerimiento '{0}'." + </span></strong><strong><span style="font-size: xx-small;">" Hash: {1}",s</span></strong><strong><span style="font-size: xx-small;">tring)state,Thread.CurrentThread.GetHashCode());</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> // Simulacion de tiempo de procesamiento</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.Sleep(2000);</span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Requerimiento '{0}' procesado",</span></strong><strong><span style="font-size: xx-small;"> (string)state);</span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglUV3fw36ExXWPZqTZGR1B3ERZB0SxavqondNN2l2JorMVo0PvfP-J7EQjydaGFwR8P1JUz710-fIOjjiQ-FbwzbQv15PF2amS4hVyQFj5GNzkZB52RNZp0MzaTog7CQYvXTJHwBcZpFo/s1600/thr3.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglUV3fw36ExXWPZqTZGR1B3ERZB0SxavqondNN2l2JorMVo0PvfP-J7EQjydaGFwR8P1JUz710-fIOjjiQ-FbwzbQv15PF2amS4hVyQFj5GNzkZB52RNZp0MzaTog7CQYvXTJHwBcZpFo/s320/thr3.jpg" tt="true" /></a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<span style="font-size: xx-small;"><span style="color: red; font-family: Arial, Helvetica, sans-serif; font-size: small;">Entendiendo mejor el problema</span></span><span style="font-size: xx-small;"></span><br />
<br />
<strong><br />
</strong><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Ahora bien, el recurso que todos queremos utilizar es el procesador.-</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br />
</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">¿Que pasara si la función que se coloca en el thread consume recursos?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br />
</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Pensemos que nosotros adrede hicimos que nuestra función NO CONSUMIESE RECURSOS de CPU (ese es el sentido de Sleep ¡!) sino que perdiese tiempo.-</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br />
</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Lo que haremos ahora es que nuestra función, en esos 2 segundos (o 2000 milisegundos que es como se lo indicamos a Sleep) trabaje compulsivamente.-</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br />
</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Para eso lo haremos iterar durante esos 2 segundos:</span><br />
<strong><br />
</strong><br />
<strong><br />
</strong><br />
<strong><br />
</strong><br />
<strong><span style="font-size: x-small;">int ticks = Environment.TickCount;</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">//Trabajar mientras no hayan transcurrido los 2 segundos</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">while(Environment.TickCount - ticks < 2000);</span></strong><br />
<strong><br />
</strong><br />
<strong><br />
</strong><br />
<strong><br />
</strong><br />
Es decir la versión de programa ahora presentara un cambio en la función llamada:<br />
<strong><br />
</strong><br />
<strong><span style="font-size: x-small;">using System;</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">using System.Threading;</span></strong><br />
<strong><span style="font-size: x-small;">namespace ThreadPoolTest</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">{</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> class MainApp</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> {</span></strong><br />
<strong><span style="font-size: x-small;"> static void Main()</span></strong><br />
<strong><span style="font-size: x-small;"> {</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> WaitCallback callBack;</span></strong><br />
<strong><span style="font-size: x-small;"> callBack = new WaitCallback(FuncionAEjecutar);</span></strong><br />
<strong><span style="font-size: x-small;"> string s;</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> for (int i=0; i < 8; i++)</span></strong><br />
<strong><span style="font-size: x-small;"> {</span></strong><br />
<strong><span style="font-size: x-small;"> s = "Hilo nro: " + i;</span></strong><br />
<strong><span style="font-size: x-small;"> ThreadPool.QueueUserWorkItem(callBack,s);</span></strong><br />
<strong><span style="font-size: x-small;"> } </span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> Console.ReadLine();</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">}</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">static void FuncionAEjecutar(object state)</span></strong><br />
<strong><span style="font-size: x-small;">{</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<span style="font-size: x-small;"><strong> Console.WriteLine("Procesando requerimiento '{0}'." + </strong><strong>" Hash: {1}",</strong></span><br />
<strong><span style="font-size: x-small;"> (string)state,Thread.CurrentThread.GetHashCode());</span></strong><br />
<strong><span style="font-size: x-small;"> </span></strong><br />
<strong><span style="font-size: x-small;"> // Simulacion de tiempo de procesamiento</span></strong><br />
<strong><span style="font-size: x-small;"> int ticks = Environment.TickCount;</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;"> //Trabajar mientras no hayan transcurrido los 2 segundos</span></strong><br />
<strong><span style="font-size: x-small;"> while(Environment.TickCount - ticks < 2000);</span></strong><br />
<span style="font-size: x-small;"><strong> </strong></span><br />
<span style="font-size: x-small;"><strong> Console.WriteLine("Requerimiento '{0}' procesado",</strong><strong>(string)state);</strong></span><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">}</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">}</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">}</span></strong><br />
<br />
Observe como el procesador inmediatamente queda sobrecargado (el efecto del while es mantenerlo “entretenido”), y la cantidad de threads se mantiene baja.<br />
<br />
<br />
Esto es porque a partir del 3er pedido, (hilo 2), los mismos no se procesan hasta que no termine el anterior y libere un thread.-<br />
<br />
Esa es la acción inteligente, que esperábamos de un broker que administre el pool de threads.-<br />
<strong><br />
</strong><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQWyzY3OGfPleboG1sPLkH5YrZ63VprEwxOOqT52worfGKOwYH5ytA3p0KMokz0x3Jrblw1q_RJfz2SObROBOpUg3lQmdNozzd4iECGTpVyJDHLzX9qYVQH1-4XYpsWoP_mqJnDvdix-0/s1600/thr4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQWyzY3OGfPleboG1sPLkH5YrZ63VprEwxOOqT52worfGKOwYH5ytA3p0KMokz0x3Jrblw1q_RJfz2SObROBOpUg3lQmdNozzd4iECGTpVyJDHLzX9qYVQH1-4XYpsWoP_mqJnDvdix-0/s320/thr4.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq82py5XlEGXlWoucy9kKyrzd_gTeAMdk6YqJImxpHXmp0E858nwEOaTJbMwITvLg4B8xhsi2FQe-xRcaBdsp5BT4xdIFV6z6Iy-jHbAHdQ6DZjePAaTEHOrjo5pDLTuSxQveuDzI7vhw/s1600/thr5.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq82py5XlEGXlWoucy9kKyrzd_gTeAMdk6YqJImxpHXmp0E858nwEOaTJbMwITvLg4B8xhsi2FQe-xRcaBdsp5BT4xdIFV6z6Iy-jHbAHdQ6DZjePAaTEHOrjo5pDLTuSxQveuDzI7vhw/s320/thr5.jpg" tt="true" /></a></div> <br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<span style="color: blue; font-size: large;">Los timers como herramientas en hilos múltiples</span> <br />
<br />
<br />
<br />
En nuestros manuales Curso MFC-II.doc y Curso MFC-III.doc hablamos de los timers de Win 32, utilizados dentro de aplicaciones C++.-<br />
La deficiencia del uso de un CONTROL timer para el control de tiempo, es que se debe reposar en técnicas no seguras para la ejecución del tick del reloj.-<br />
Esto es porque los eventos levantados por este control (o API o clase dependiendo de cómo lo utilice) son sincrónicos respecto de la aplicación que lo ha instanciado.-<br />
<br />
Es decir, se debe esperar que la aplicación Windows (es decir hace falta una aplicación con ventanas) pase el control a la ronda de atención de mensajes de Windows y allí sea atendido por el mensaje WM_TIMER.-<br />
Esto significa que si la aplicación esta ocupada en otras tareas y su tiempo de ronda de atención, supera al del evento Elapsed(periodo a controlar) del control Timer, este perderá 1 o mas rondas de ejecución.-<br />
<br />
<br />
En el Framework .NET existen 3 tipos de Timers.-<br />
<br />
<strong>Server Based Timers</strong><br />
<br />
Uno es el que se ve en la solapa Componentes del Toolbox.-<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwxOd_msGpsZ-0EoCX7phtlTcBFuh8BcMX-tniz74iSt7coyz5UaFhPkh0xZ9bk3VYi4ggiWuwKpPuVhSAHHj21X558rwGFDSd65NKGcy70vEgl56Nyao-Tr-BMifbKRO9l1LzN62MW7g/s1600/thr6.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwxOd_msGpsZ-0EoCX7phtlTcBFuh8BcMX-tniz74iSt7coyz5UaFhPkh0xZ9bk3VYi4ggiWuwKpPuVhSAHHj21X558rwGFDSd65NKGcy70vEgl56Nyao-Tr-BMifbKRO9l1LzN62MW7g/s320/thr6.jpg" tt="true" /></a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Este timer es llamado timer basado en servidor.-<br />
<br />
<br />
Puede trabajar indistintamente con Windows Forms o con servicios batch (sin interacción con el usuario) y se encuentra en la biblioteca de clases llamada System.Timers.Timer<br />
<br />
Esta diseñado para trabajar con hilos multiples y en los hilos llamados “de trabajo” (worker threads) que son aquellos que no atienden servicios de interfaz con el usuario.-<br />
<br />
Su arquitectura difiere de la anterior, al punto que son más exactos que los Windows timers.-<br />
<br />
Pero la diferencia esencial es que el mismo timer puede manejar un evento levantado en OTRO THREAD.- <br />
<br />
<br />
<br />
<strong>Windows Timer</strong><br />
<br />
El segundo es el control de tiempo basado en ventanas de Windows y es una actualizacion del que existe desde las primeras versiones de Visual Basic.<br />
<br />
Es una versión idéntica a la de los controles timer de WIN 32 y esta pensada solo para trabajar con Windows.Forms, y se encuentra en la biblioteca de clases llamada System.Windows.Forms.Timer.-<br />
<br />
Este timer (Windows Timer) esta diseñado para ambientes de hilo unico (single threaded) que es el unico en el que puede trabajar Visual Basic 6.0 y anteriores.-<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipW39Fdb45Ud6Soil0k28JpwPKJ92Ji2rtMHgkp-D7Zte4fG8qgQcNwSzWZe30fv5PCpGWQp-KDOUtkT4hOZdq3YIR-5rOEwS0qVuShbYwfMmDwEo1xhiUxn2yOUZ8JjSIOfJsqGLAG_w/s1600/thr7.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipW39Fdb45Ud6Soil0k28JpwPKJ92Ji2rtMHgkp-D7Zte4fG8qgQcNwSzWZe30fv5PCpGWQp-KDOUtkT4hOZdq3YIR-5rOEwS0qVuShbYwfMmDwEo1xhiUxn2yOUZ8JjSIOfJsqGLAG_w/s200/thr7.jpg" tt="true" width="200" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><strong>Thread Timers</strong></div><br />
<br />
EL tercero es un timer para trabajo con hilos. Es el que utilizaremos en nuestros ejemplos y utiliza metodos de llamadas a funciones como parametros (callbacks).-<br />
Este timer no tiene un control accesible como componente C# o de un Form y solo puede especificarse programaticamente.-<br />
Las versiones del timer para trabajos con hilos, utilizaran las utilidades que figuran en el namespace System en System.Threading.Timer.-<br />
El siguiente ejemplo al que llamaremos Timers_1 nos muestra algunos aspectos interesantes del uso de los timers de la biblioteca mencionada.-<br />
El main instancia un objeto de la clase que crea los timers: <br />
<br />
<strong><span style="font-size: xx-small;">PruebaTimer test = new PruebaTimer();</span></strong><br />
<br />
Envia un mensaje por la consola:<br />
<br />
<strong><span style="font-size: xx-small;">Console.WriteLine("Timer iniciado por 6 segundos.");</span></strong><br />
<br />
y luego permite la ejecucion de los threads levantados en el constructor de la clase PruebaTimer<br />
<br />
<span style="font-size: x-small;"><strong>using System.Threading;</strong></span> <br />
<span style="font-size: x-small;"><strong></strong></span><br />
<span style="font-size: x-small;"><strong>namespace Timers_1</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>{</strong></span><br />
<span style="font-size: x-small;"><strong> public class PruebaTimer</strong></span><br />
<span style="font-size: x-small;"><strong> {</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> public ManualResetEvent timerevent;</strong></span><br />
<span style="font-size: x-small;"><strong> public PruebaTimer()</strong></span><br />
<span style="font-size: x-small;"><strong> {</strong></span><br />
<span style="font-size: x-small;"><strong> timerevent = new ManualResetEvent(false);</strong></span><br />
<span style="font-size: x-small;"><strong> //El primer timer trabaja CADA 5 segundos y en cada lapso</strong></span><br />
<span style="font-size: x-small;"><strong> //invoca al metodo Metodotimer1</strong></span><br />
<span style="font-size: x-small;"><strong> </strong></span><br />
<span style="font-size: x-small;"><strong> Timer timer = new Timer(</strong></span><span style="font-size: x-small;"><strong>new TimerCallback(this.MetodoTimer1),</strong></span><br />
<strong><span style="font-size: x-small;"> null, </span></strong><span style="font-size: x-small;"><strong>TimeSpan.FromSeconds(5), </strong></span><span style="font-size: x-small;"><strong>TimeSpan.FromSeconds(5));</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>//El segundo timer trabaja CADA 1 segundo y en cada lapso</strong></span><br />
<span style="font-size: x-small;"><strong>//invoca al metodo Metodotimer2</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>Timer Timer2 = new Timer(</strong></span><span style="font-size: x-small;"><strong>new TimerCallback(this.MetodoTimer2),</strong></span><br />
<strong><span style="font-size: x-small;"> null, </span></strong><span style="font-size: x-small;"><strong>TimeSpan.FromSeconds(1), </strong></span><span style="font-size: x-small;"><strong>TimeSpan.FromSeconds(1)</strong></span><span style="font-size: x-small;"><strong>);</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> }</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> public void MetodoTimer1(object state)</strong></span><br />
<span style="font-size: x-small;"><strong> {</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> Console.WriteLine("\nEn el 6to segundo,el Timer invoca este metodo.");</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> timerevent.Set();</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> }</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>public void MetodoTimer2(object state)</strong></span><br />
<span style="font-size: x-small;"><strong>{</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> Console.Write(".");</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>}</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>public static void Main()</strong></span><br />
<span style="font-size: x-small;"><strong>{</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> PruebaTimer test = new PruebaTimer();</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> Console.WriteLine("Timer iniciado por 6 segundos.");</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> //Bloquea el thread principal hasta que reciba la señal</strong></span><br />
<span style="font-size: x-small;"><strong> //del thread hijo (en este caso el creado con PruebaTimer)</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> test.timerevent.WaitOne();</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> Console.WriteLine("Mientras no Pulse ENTER para terminar, el timer seguira ejecutandose");</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong> Console.ReadLine();</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>}</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>}</strong></span><br />
<span style="font-size: x-small;"><br />
<strong></strong></span><br />
<span style="font-size: x-small;"><strong>}</strong></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4D8ov-8lOWlgVdJ4WXWMfSAwReKO9a9siAy1vBPCns57OFBqhrwk8Hmvl-tzdRqFJ783vev_jwRCqQk7rTEDMf08PHe4fIouGGHzQQJ9_zQCV311zF3BDFV-iHdrOdooxurglkLE3i_I/s1600/thr8.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4D8ov-8lOWlgVdJ4WXWMfSAwReKO9a9siAy1vBPCns57OFBqhrwk8Hmvl-tzdRqFJ783vev_jwRCqQk7rTEDMf08PHe4fIouGGHzQQJ9_zQCV311zF3BDFV-iHdrOdooxurglkLE3i_I/s320/thr8.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div>Observemos lo que nos informa la ejecucion del programa en su salida por la consola:<br />
<br />
<br />
A) Primero se ejecuta la sentencia del main, pese a haber instanciado previsamente un objeto de la clase Timer. Esto sucedera hasta que el thread del main quede bloqueado y eso permita a los otros threads seguir ejecutandose.-<br />
El bloqueo del thread del main se produce al ser invocado el metodo WaitOne del atributo publico timerEvent de la clase PruebaTimer.-<br />
<br />
…<br />
<br />
<strong><span style="font-size: x-small;">test.timerevent.WaitOne();</span></strong><br />
<br />
…<br />
<br />
<br />
<br />
B) Luego se ejecutan los metodos llamados por los timers.-<br />
<br />
Se observa que lo hacen en estricto orden de creacion .Es decir primero el metodo llamado el primer timer instanciado y luego el metodo del segundo timer instanciado.-<br />
<strong><span style="font-size: x-small;">…</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">Timer timer = new Timer(new TimerCallback(this.MetodoTimer1),</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">…..</span></strong><br />
<br />
…<br />
<br />
<strong><span style="font-size: x-small;">Timer Timer2 = new Timer(n</span></strong><strong><span style="font-size: x-small;">ew TimerCallback(this.MetodoTimer2),</span></strong><br />
<br />
….<br />
<br />
<br />
C) Finalmente observemos que en la instanciacion del timer, se coloca no solo el metodo que sera invocado en cada lapso, sino ademas cada cuanto tiempo, dicho lapso se ejecuta.-<br />
<br />
<strong><span style="font-size: x-small;">//El primer timer trabaja CADA 5 segundos y en cada lapso</span></strong><br />
<strong><span style="font-size: x-small;">//invoca al metodo Metodotimer1</span></strong><br />
<strong><br />
<span style="font-size: x-small;"></span></strong><br />
<strong><span style="font-size: x-small;">Timer timer = new Timer(new TimerCallback(this.MetodoTimer1),</span></strong><br />
<strong><span style="font-size: x-small;"> null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));</span></strong><br />
<br />
<br />
<br />
D) El modo en el que los threads se informan del inicio y fin de su actrividad, permite una sincronizacion simple.<br />
<br />
En el ejemplo elegimos usar la clase ManualResetEvent que:<br />
<br />
1- Nos permite a traves de WaitOne detener un thread bloquendo su ejecucion y permitiendo que otros threads encolados puedan ejecutarse<br />
<br />
2- Y a traves de Set nos permiter levantar una señal indicando la finalizacion de la tarea de un thread para que el que estaba bloqueado continue.-<br />
<br />
E) La ejecucion nos muestra que el timer, una vez que está levantado, se ejecuta con periodicidad, pese a que el thread principal es el que tiene nuevamente el control.-<br />
<br />
Se puede observar que los metodos llamados en cada lapso (eventos) son ejecutados hasta que se pulsa la tecla ENTER.-Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com0tag:blogger.com,1999:blog-4330427453885266705.post-35273095293850549242010-04-24T12:34:00.000-07:002010-04-24T13:38:06.776-07:00Algo sobre Threads en C#-Nota 1OBJETIVO <br />
<br />
Revisar algunos conceptos sobre hilos en C#(multiple threading).-<br />
<br />
Ejecución de Hilos Múltiples en un proceso<br />
<br />
<br />
El uso de hilos de ejecución dentro de un proceso presenta esencialmente ventajas en los programas con interacción con el usuario.-<br />
El punto básico es que mientras se ejecuta una tarea, el programa comienza a atender otra en paralelo.-<br />
Esto hace que quien interactúa con el programa no quede a la espera de la ejecución de una tarea que puede ejecutarse en trasfondo (background), mientras continua con su trabajo.-<br />
<br />
Bien, este es el marco general que podemos extender no solo a aplicaciones interactivas sino también a procesos batch.-<br />
<br />
Ahora bien, ¿es todo TAN SIMPLE como “simular” que tenemos mas de un procesador atendiendo una tarea?<br />
<br />
¿Se trata solo de abrir otro hilo de ejecución y “mágicamente” toda la operación se acelera como si tuviese dos procesadores atendiendo?<br />
<br />
Veamos un poco más en detalle el tema con el esquema siguiente.-<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0ej7YDsWcStTCrZklxHKRFR1JnBln6yVH0_EbuMZoIh2S2vXTSNnUXaj41Cl4tHfRbh8wrPykSQJmpF9oCp02bkJDL9Wqy_rkuDPiuSs9oRyD3WOCWqT58MDuGHp5aTJ29eMdf-nN4Wg/s1600/thr1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0ej7YDsWcStTCrZklxHKRFR1JnBln6yVH0_EbuMZoIh2S2vXTSNnUXaj41Cl4tHfRbh8wrPykSQJmpF9oCp02bkJDL9Wqy_rkuDPiuSs9oRyD3WOCWqT58MDuGHp5aTJ29eMdf-nN4Wg/s320/thr1.jpg" tt="true" width="320" /></a></div><br />
Imaginemos un proceso que actúa como un servidor de pedidos y que se ejecuta en un solo hilo de ejecución.-<br />
<br />
<br />
Observamos, y esperamos, que cada pedido se encola, el primero que ingresa es el primero que se atiende y solo se pasa al siguiente cuando se finaliza con el anterior.-<br />
Ahora bien, un programa como el que mostramos difícilmente utilice un solo recurso de la computadora.-<br />
¿Que queremos decir con esto?<br />
Que si por ejemplo el programa esta atendiendo el pedido 1 (Hilo 1) y, dentro de sus tareas esta una pesada consulta a la base de datos, el pedido quedara detenido hasta que la consulta haya sido satisfecha (por otro recurso u otro proceso), pero mientras tanto mantiene encolados a los demás pedidos, AUN CUANDO NO UTILICE COMPLETAMENTE, POR EJEMPLO, EL PROCESADOR.-<br />
<br />
Esta idea se extiende a cualquier otro recurso (discos, impresoras, lectores ópticos, canales de entrada de información, etc.) que un proceso deba utilizar.-<br />
<br />
Surge entonces la idea de: ¿por que no usar los recursos que este hilo no utiliza en este momento?<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwH9qy-M_u6z893YGnMxGSG3G5w1bBfkiyaP1TbENYa0JYqmDwEqMzkvdxl2HkW_wWI6KZfcWRd3u9LzupeOL_vUACkYBWxMox9NF7wklkW68-UNiM0a3u4DZMSrsDgUDEhnKcOZmqjnQ/s1600/thr3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwH9qy-M_u6z893YGnMxGSG3G5w1bBfkiyaP1TbENYa0JYqmDwEqMzkvdxl2HkW_wWI6KZfcWRd3u9LzupeOL_vUACkYBWxMox9NF7wklkW68-UNiM0a3u4DZMSrsDgUDEhnKcOZmqjnQ/s320/thr3.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div> En esta técnica hemos GENERADO un nuevo thread por cada pedido.-<br />
<br />
<br />
Debemos ser cuidadosos en este tipo de decisiones.-<br />
Si el proceso que tenemos en nuestro programa, es simple,entonces un aumento en el numero de llamadas a la función a través de nuevos threads, puede generar una sobrecarga inesperada: <strong>Que el cambio de contexto (intercambio entre los threads) demore mas tiempo que la función que se ejecuta en el thread.-</strong><br />
Con esto tenemos uno de los peores escenarios, ya que a medida que se aumenta el uso del sistema (escalabilidad), el tiempo de espera comienza a aumentar lineal o geométricamente impidiendo que el sistema pueda escalarse de modo armonioso.-<br />
<br />
Esto es así ya que el Thread es una “simulación” de procesamiento múltiple paralelo. La verdadera ejecución en paralelo solo puede hacer con procesadores dedicados a cada hilo del proceso.-<br />
Aun en el caso de tener más de un procesador podemos llegar al escenario que se plantea en el párrafo anterior. Aunque por supuesto el sistema en su conjunto admitiría una carga mayor antes de llegar a esa situación -<br />
<br />
<span style="font-size: large;">Un modelo con multiples threads</span> <br />
<br />
<br />
Los hilos en Windows tienen el siguiente esquema:<br />
Una aplicación comienza con un thread (hilo) específico: que es su hilo de ejecución.-<br />
Esto le asigna (al proceso) memoria, espacio en la pila y desde ya tiempo de procesador.-<br />
<br />
Puede luego expandir otros hilos.-<br />
Windows tiene un planificador de tareas que divide el tiempo de CPU entre los threads activos.<br />
Toda la planificación se hace estrictamente por prioridad. El planificador elige el hilo de mayor prioridad y lo ejecuta.-<br />
<br />
Si la computadora tiene un solo procesador, este tiempo se reparte entre ellos. Unos párrafos mas adelante explicamos de un modo bastante general como se realiza esta tarea.-<br />
Si la computadora tiene mas de un procesador, cada uno de ellos atenderá un thread por ronda del scheduler. Es decir que si hubiese N procesadores (en un sistema multiprocesador) los N primeros threads ejecutables serán ejecutados. <br />
<br />
<span style="font-size: large;">Prioridades</span><br />
<br />
<br />
La prioridad utilizada para hacer estas decisiones es la prioridad dinámica del thread.-<br />
Cada proceso ejecutable tiene una base de prioridad para ser ejecutado. Cada thread tiene también una base de prioridad que es función de la base de prioridad del proceso que la dispara. Decimos que es función de el porque es ajustable en:<br />
<br />
<br />
<br />
- 1 o 2 puntos por sobre su proceso base<br />
<br />
- igual a su proceso base<br />
<br />
- 1 o 2 puntos por debajo de su proceso base.-<br />
<br />
<br />
<br />
Este ajuste de prioridad esta expuesto a través de las API de Win32.-<br />
Además de la prioridad base, todos los threads tienen una prioridad dinámica que NUNCA es menor QUE LA PRIORIDAD BASE. El sistema aumenta y decrementa esta prioridad base según sus necesidades.-<br />
Esto lo hace para resolver un interesante caso de multiprocesamiento:<br />
Cuando el kernel del sistema operativo esta eligiendo cual es el thread que va a ejecutar en el procesador, elige aquel que tenga la variable dinámica más alta (esto es el de prioridad dinámica mas alta).-<br />
Pensemos un caso donde 3 hilos: T1, T2 y T3 con prioridades crecientes.-<br />
T1, el de mayor prioridad esta listo para ser programado, mientras que T3 (el de menor prioridad) se esta ejecutando en una sección critica.(Mas adelante explicamos que son las secciones criticas)-<br />
Ahora T1 queda esperando que T3 libere un recurso compartido (cualquiera).-<br />
Entonces T2 toma todo el tiempo del procesador ya que T1 esta ocupado esperando el recurso que debe liberar T3.-<br />
Como T3 no es de alta prioridad en este esquema no es atendido.<br />
<br />
Lo que significa que no puede salir de la sección critica ya que no puede ser programado por el scheduler.-<br />
AL no salir de esa sección, no libera el recurso compartido y T1 no puede seguir ejecutándose.-<br />
Para resolver esto, el planificador (scheduler) de Windows resuelve esto invirtiendo de modo aleatorio las prioridades de los threads que están listos para ser ejecutados. De este modo se deja al thread T3 ejecutarse el tiempo suficiente para liberar el recurso que estará esperando T1.-<br />
<br />
<br />
Si el hilo de baja prioridad (T3) no tuvo tiempo suficiente de liberar su bloqueo, se le dará otra oportunidad en la próxima ronda.-<br />
<br />
<br />
<br />
<span style="font-size: large;">Tiempo de atención</span><br />
<br />
Cuando el thread esta planificado para correr en el procesador tiene asignada una cantidad (quantum en la jerga técnica) de tiempo para ejecutarse. Realmente se le entrega a cada uno 2 unidades de quantum (algo así como 10ms en r4000 y 15ms en x86).-<br />
El quantum (tiempo de atención) de un thread, resulta decrementado cuando en una interrupción del reloj del procesador, se descubre que esta corriendo. En ese momento su quantum se decrementa en 1.-<br />
Cuando el quantum de un thread llega a cero, su prioridad dinámica se decrementa en 1, SOLO en el caso en que esta no coincida con la prioridad base. En ese caso también el quantum del thread es reasignado al valor de la prioridad base. Todo este proceso es para intentar asegurar un balance en los tiempos de atención-<br />
Si ocurre un cambio de prioridad, entonces el scheduler ubica el thread de máxima prioridad que esta listo para correr.<br />
<br />
Sino el thread se coloca al final de la cola de ejecución de su prioridad permitiendo que otros threads de la misma prioridad se planifiquen para ser corridos en un proceso conocido como “round robin”.-<br />
En C#, la clase Thread permite que generemos hilos múltiples con responsabilidad de nuestro programa de no generar una situación como la indicada en el párrafos anteriores.-<br />
<br />
Una vez creado el thread se utilizara ThreadStart para indicar cual es el código del programa que se ejecuta en el thread.<br />
Durante la duración de su existencia, un thread esta en uno o mas de los estados definidos en ThreadState. <br />
<br />
La calificación de nivel de prioridad del scheduler se define en ThreadPriority, pero no hay garantía que el sistema operativo pueda respetarla.-<br />
GetHashCode provee un mecanismo simple de identificación de los threads en ejecución.-<br />
Durante la vida del thread en el proceso este identificador es exclusivo del thread. El valor de GetHashCode no tiene relación con el ThreadId que el Sistema operativo asigna al mismo.-<br />
Veamos un ejemplo que nos permitirá ensayar algunas variantes y entender como funcionan los threads.-<br />
En este programa el thread principal (el del método Main) arranca 2 nuevos threads.-<br />
<br />
<br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><strong>Thread t1 = new Thread(new ThreadStart(ProcesoDelThread1));</strong></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><br />
<span style="font-size: x-small;"><strong></strong></span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><br />
<span style="font-size: x-small;"><strong></strong></span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><br />
<span style="font-size: x-small;"><strong></strong></span></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><strong>Thread t2 = new Thread(new ThreadStart(ProcesoDelThread2));</strong></span><br />
<br />
<br />
<br />
Cada thread responderá a la ejecución de 2 métodos (ProcesoDelThread1 y ProcesoDelThread2).-<br />
Hasta allí el esquema es simple.-<br />
<br />
Pero hemos hecho una diferencia operativa entre ambas funciones.-<br />
El método llamado por el primer Thread (ProcesoDelThread1) consume tiempo de procesador en el momento en el que le toca trabajar, mientras que el método llamado por el segundo Thread (ProcesoDelThread2) es mas “solidario”. Comparte su tiempo de ejecución con los otros threads del mismo proceso.-<br />
<br />
<br />
Es decir en el primer thread (t1 -> ProcesoDelThread1) el código procura ejecutar su tarea sin compartir su tiempo de ejecución con otros procesos.-<br />
<br />
El while se encarga de eso:<br />
<br />
<br />
<span style="font-size: xx-small;"><strong> int c = 0;</strong></span><br />
<span style="font-size: xx-small;"><strong>//Consumir procesador<br />
while(c < T_MAX)</strong></span><br />
<span style="font-size: xx-small;"><strong> c++;</strong></span><br />
Pero en el segundo thread (t2 -> ProcesoDelThread2) el codigo esta escrito permitiendo compartir el uso del procesador durante la ejecución DEL MISMO THREAD (es decir comparte sin esperar a terminar).-<br />
<br />
El metodo Sleep es el que se encarga de esto<br />
<br />
<strong><span style="font-size: x-small;">Thread.Sleep(0);</span></strong><br />
<br />
Para observar el mismo efecto en el thread principal, hemos agregado una condición dentro de la iteración principal:<br />
<br />
<br />
<strong><span style="font-size: xx-small;">for (int i = 0; i < 8; i++) </span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Thread Principal: Haciendo algo en la vuelta {0}.", i);</span></strong><br />
<strong><span style="font-size: xx-small;"> if (i> 4)</span></strong><br />
<strong><span style="font-size: xx-small;"> //Dejar que otros se ejecuten</span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.Sleep(0);</span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<br />
<br />
Es decir a partir de ejecutada la 6ta (las vueltas 0 a 4 no cumplen la condición y la 5ta la cumple, pero ejecuta parte de su tarea antes de compartir tiempo de procesador).-<br />
<br />
<br />
<br />
<br />
Ejecute el código que figura a continuación como una aplicación de consola y compruebe la salida.-<br />
<br />
<br />
<br />
<strong><span style="font-size: xx-small;">using System;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">using System.Threading;</span></strong><br />
<strong>//<br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">// Un escenario de thread simple :comenzar metodos estaticos corriendo</span></strong><br />
<strong><span style="font-size: xx-small;">// en otros dos threads</span></strong><br />
<strong><span style="font-size: xx-small;">// En este ejemplo cuando existe un unico procesor en la computadora en la que se ejecuta</span></strong><br />
<strong><span style="font-size: xx-small;">// el thread no utiliza tiempo del procesador, hasta que el proceso principal se lo permite</span></strong><br />
<strong><span style="font-size: xx-small;">// Esto se logra cuando utilizamos el metodo estatico sleep de la clase Thread.-</span></strong><br />
<strong><span style="font-size: xx-small;">//</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">public class ThreadExample </span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> const int T_MAX = 200;</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">// Esta funcion llamada por el thread1 no permite que otros threads se ejecuten</span></strong><br />
<strong><span style="font-size: xx-small;">//Hasta que el termine</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">public static void ProcesoDelThread1() </span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">for (int i = 0; i < 10; i++) </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Proceso Hijo llamado ProcesoDelThread1: {0}", i);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">// </span></strong><br />
<strong><span style="font-size: xx-small;"> int c= 0;</span></strong><br />
<strong><span style="font-size: xx-small;"> //Consumir procesador</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> while (c < T_MAX) c++;</span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<br />
<strong><span style="font-size: xx-small;">//Esta funcion llamada por el thread2 deja en cada iteracion un tiempo para</span></strong> <br />
<strong><span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">//la ejecucion de otros threads</span></strong><br />
<br />
<strong><span style="font-size: xx-small;">public static void ProcesoDelThread2() </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">for (int i = 0; i < 12; i++) </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Proceso Hijo llamado ProcesoDelThread2: {0}", i);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> // Indicar que el thread debe suspenderse para permitir que otros</span></strong><br />
<strong><span style="font-size: xx-small;"> // se ejecuten</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.Sleep(0);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> //Realizar el trabajo restante</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Segunda parte de ProcesoDelThread2: {0}", i);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<br />
<strong><span style="font-size: xx-small;">public static void Main() </span></strong><br />
<strong><span style="font-size: xx-small;"></span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Thread t1 = new Thread(new ThreadStart(ProcesoDelThread1));</span></strong><br />
<strong><span style="font-size: xx-small;">Thread t2 = new Thread(new ThreadStart(ProcesoDelThread2));</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">//Iniciar los threads</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.WriteLine("Thread Principal: Inicia thread hijo t2");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">t2.Start();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.WriteLine("Thread Principal: Inicia thread hijo t1");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">t1.Start();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">for (int i = 0; i < 8; i++) </span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">{</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> Console.WriteLine("Thread Principal: Haciendo algo en la vuelta {0}.", i);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;"> if (i> 4)</span></strong><br />
<strong><span style="font-size: xx-small;"> //Dejar que otros se ejecuten</span></strong><br />
<strong><span style="font-size: xx-small;"> Thread.Sleep(0);</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.WriteLine("Thread Principal: llamo al metodo Join(), para esperar" +</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">" que la funcion del primer thread termine");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">t2.Join();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.WriteLine("Thread Principal: Retorno de la ejecucion"+</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">" del segundo thread. Pulse ENTER para terminar");</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">Console.ReadLine();</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<strong><br />
<span style="font-size: xx-small;"></span></strong><br />
<strong><span style="font-size: xx-small;">}</span></strong><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYoWme7cbLK-AKmq_PP5A14u5JYxJfL7cYoJUBidSmca0d83qYPPKbYBSRTRfwj2u34Ex0Okjp974LSfoyGo-3JCAMmFKVG_Xug07iY4UHr7t4YwVO9RhMm4KwcnOFcHPipFVK8B-GZDs/s1600/thr4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYoWme7cbLK-AKmq_PP5A14u5JYxJfL7cYoJUBidSmca0d83qYPPKbYBSRTRfwj2u34Ex0Okjp974LSfoyGo-3JCAMmFKVG_Xug07iY4UHr7t4YwVO9RhMm4KwcnOFcHPipFVK8B-GZDs/s320/thr4.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div>Veamos esto por partes para tener un mejor entendimiento<br />
<br />
Las primeras líneas de salida corresponden a la ejecución del thread principal y de su ciclo for, hasta la vuelta numero 6 (es decir i == 5).-<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhafEVj8CzWCZlchxwY3AlqApeP4bq8VuFykwS79fpGmJS65bcwYBxrC5lmgw1m2UkX30Sja7rz0nHDfTwBfW6899bKLWBdmIXlDWtt2q6rYeVOViIGZW2HFFfBXkjDjXVCNO0TuMd-Pm4/s1600/thr5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhafEVj8CzWCZlchxwY3AlqApeP4bq8VuFykwS79fpGmJS65bcwYBxrC5lmgw1m2UkX30Sja7rz0nHDfTwBfW6899bKLWBdmIXlDWtt2q6rYeVOViIGZW2HFFfBXkjDjXVCNO0TuMd-Pm4/s320/thr5.jpg" tt="true" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><br />
</div>En esa vuelta se cumple la condición que permitirá compartir el tiempo de procesamiento<br />
Allí se da tiempo para ejecutar el trabajo de t2.-<br />
<br />
Lo que efectivamente sucede, PERO OBSERVE QUE INMEDIATAMENTE se permite que el thread principal continúe (“Thread principal haciendo algo en la vuelta 6”)-<br />
Como el thread principal es también cortés, vera que luego de esto el procesador vuelve a atender al thread t2 y allí este termina su primer vuelta realizando la segunda parte de su trabajo (“Segunda parte de ProcesoDelThread2: 0”).-<br />
<br />
Pero a partir de alli, la cortesía del thread principal y de t2, no tiene nada que hacer con la “avaricia” de t1.-<br />
Este arranca y hasta que no termina su tarea no permitirá que otro thread realice su trabajo.-<br />
<br />
<br />
<br />
En esa vuelta se cumple la condición que permitirá compartir el tiempo de procesamiento<br />
<br />
<br />
<br />
Allí se da tiempo para ejecutar el trabajo de t2.-<br />
<br />
<br />
<br />
<br />
<br />
Lo que efectivamente sucede, PERO OBSERVE QUE INMEDIATAMENTE se permite que el thread principal continúe (“Thread principal haciendo algo en la vuelta 6”)-<br />
<br />
<br />
<br />
Como el thread principal es también cortés, vera que luego de esto el procesador vuelve a atender al thread t2 y allí este termina su primer vuelta realizando la segunda parte de su trabajo (“Segunda parte de ProcesoDelThread2: 0”).-<br />
<br />
Pero a partir de alli, la cortesía del thread principal y de t2, no tiene nada que hacer con la “avaricia” de t1.-<br />
Este arranca y hasta que no termina su tarea no permitirá que otro thread realice su trabajo.-<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkW7Mygbf0y4-lqndeKbwlEJ2QKwzvWxTpWgD40DKbixeM5ZALxr5fGs2rLMZG1VLrYFJ9de0i5IloRP8cHPu0GC1OXsk_OyvQlExPKix3eBMch7C7Ap0krskZsEYcHp_GftizYwZ3Xbc/s1600/thr5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkW7Mygbf0y4-lqndeKbwlEJ2QKwzvWxTpWgD40DKbixeM5ZALxr5fGs2rLMZG1VLrYFJ9de0i5IloRP8cHPu0GC1OXsk_OyvQlExPKix3eBMch7C7Ap0krskZsEYcHp_GftizYwZ3Xbc/s320/thr5.jpg" tt="true" /></a></div> <br />
Ahora bien, no parece cómodo tener que colocar un Thread.Sleep(0), por ahí, a los efectos de simular multiprocesamiento.- <br />
<br />
Esto puede hacerse en ciertos métodos pero quizás no es útil en la mayoría<br />
<br />
(Sigue en Algo sobre Threads en C#-Nota 2)Eduardobhttp://www.blogger.com/profile/10528374798695418539noreply@blogger.com1