日期:2011-03-22 16:16:00 来源:本站整理
<b>java服务器操纵</b>[Java编程]
本文“<b>java服务器操纵</b>[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
目前谈论一下服务器利用(程序)的问题,我把它叫作NameCollecor(名字汇集器).假定多名用户同时尝试提交他们的E-mail地址,那么会发生什么情形呢?若NameCollector利用TCP/IP套接字,那么必须应用早先介绍的多线程机制来实现对多个客户的并发掌握.但全部这些线程都试图把数据写到同一个文件里,此中保存了全部E-mail地址.这便要求我们设立一种锁定机制,保证多个线程不会同时拜候那个文件.一个“信号机”可在这里帮忙我们到达目的,但大概还有一种更简单的方法.
假如我们换用数据报,就没必要利用多线程了.用单个数据报便可“侦听”进入的全部数据报.一旦监督到有进入的消息,程序就会举行得当的处理,并将答复数据作为一个数据报传回原先发出恳求的那名接纳者.若数据报半路上丧失了,则用户会注意到没有答复数据传回,所以可以重新提交恳求.
服务器利用收到一个数据报,并对它举行解读的时刻,必须提取出此中的电子信件地址,并查抄本机保存的数据文件,看看里面能否已经包含了那个地址(假如没有,则增添上).所以我们目前碰到了一个新的问题.Java 1.0仿佛没有充足的本领来便利地处理包含了电子信件地址的文件(Java 1.1则不然).但是,用C简单便可以办理这个问题.因此,我们在这儿有机会学习将一个非Java程序同Java程序衔接的最简便方法.程序利用的Runtime对象包含了一个名为exec()的办法,它会独立机械上一个独立的程序,并返回一个Process(进程)对象.我们可以获得一个OutputStream,它同这个单独程序的尺度输入衔接在一同;并获得一个InputStream,它则同尺度输出衔接到一同.要做的全部事情就是用任何语言写一个程序,只要它能从尺度输入中获得自己的输入数据,并将输出后果写入尺度输出便可.假若有些问题不能用Java简便与快速地办理(大概想操纵原有代码,不想改写),便可以考虑采取这种办法.亦可以利用Java的“固有办法”(Native Method),但那要求更多的本领,大家可以参考一下附录A.
1. C程序
这个非Java利用是用C写成,因为Java不适合作CGI编程;最少启动的时间不能让人称心.它的任务是管理电子信件(E-mail)地址的一个列表.尺度输入会承受一个E-mail地址,程序会查抄列表中的名字,判断能否存在那个地址.若不存在,就将其加入,并报告操作成功.但假定名字已在列表里了,就需求指出这一点,避免反复加入.大家没必要耽忧自己不能完好理解下列代码的含义.它仅仅是一个演示程序,奉告你若何用其他语言写一个程序,并从Java中调用它.在这里具体采取何种语言并不重要,只要可以从尺度输入中读取数据,并能写入尺度输出便可.
//: Listmgr.c // Used by NameCollector.java to manage // the email list file on the server #include <stdio.h> #include <stdlib.h> #include <string.h> #define BSIZE 250 int alreadyInList(FILE* list, char* name) { char lbuf[BSIZE]; // Go to the beginning of the list: fseek(list, 0, SEEK_SET); // Read each line in the list: while(fgets(lbuf, BSIZE, list)) { // Strip off the newline: char * newline = strchr(lbuf, '\n'); if(newline != 0) *newline = '\0'; if(strcmp(lbuf, name) == 0) return 1; } return 0; } int main() { char buf[BSIZE]; FILE* list = fopen("emlist.txt", "a+t"); if(list == 0) { perror("could not open emlist.txt"); exit(1); } while(1) { gets(buf); /* From stdin */ if(alreadyInList(list, buf)) { printf("Already in list: %s", buf); fflush(stdout); } else { fseek(list, 0, SEEK_END); fprintf(list, "%s\n", buf); fflush(list); printf("%s added to list", buf); fflush(stdout); } } } ///:~
该程序假定C编译器能承受'//'款式注释(很多编译器都能,亦可换用一个C++编译器来编译这个程序).假如你的编译器不能承受,则简单地将那些注释删掉便可.
文件中的第一个函数查抄我们作为第二个参数(指向一个char的指针)传送给它的名字能否已在文件中.在这儿,我们将文件作为一个FILE指针传送,它指向一个已翻开的文件(文件是在main()中翻开的).函数fseek()在文件中遍历;我们在这儿用它移至文件开首.fgets()从文件list中读入一行内容,并将其置入缓冲区lbuf——不会超越规定的缓冲区长度BSIZE.全部这些工作都在一个while循环中举行,所以文件中的每一行城市读入.接下来,用strchr()找到新行字符,以便将其删掉.最后,用strcmp()对比我们传送给函数的名字与文件中的当前行.若找到一致的内容,strcmp()会返回0.函数随后会退出,并返回一个1,指出该名字已经在文件里了(注意这个函数找到符合内容后会当即返回,不会把时间浪费在查抄列表剩余内容的上面).假如找遍列表都没有发现符合的内容,则函数返回0.
在main()中,我们用fopen()翻开文件.第一个参数是文件名,第二个是翻开文件的方法;a+表示“追加”,以及“翻开”(或“成立”,假如文件尚不存在),以便到文件的末尾举行更新.fopen()函数返回的是一个FILE指针;若为0,表示翻开操作失利.此时需求用perror()打印一条出错提醒消息,并用exit()中止程序运行.
假如文件成功翻开,程序就会进入一个无限循环.调用gets(buf)的函数会从尺度输入中取出一行(记着尺度输入会与Java程序衔接到一同),并将其置入缓冲区buf中.缓冲区的内容随后会简单地传送给alreadyInList()函数,如内容已在列表中,printf()就会将那条消息发给尺度输出(Java程序正在监督它).fflush()用于对输出缓冲区举行革新.
假如名字不在列表中,就用fseek()移到列表末尾,并用fprintf()将名字“打印”到列表末尾.随后,用printf()指出名字已成功加入列表(一样需求革新尺度输出),无限循环返回,持续等候一个新名字的进入.
记着普通不能先在自己的计算机上编译此程序,再把编译好的内容上载到Web服务器,因为那台机械利用的大概是差别类的处理器和操作系统.比方,我的Web服务器安装的是Intel的CPU,但操作系统是Linux,所以必须先下载源码,再用远程号令(通过telnet)批示Linux自带的C编译器,令其在服务器端编译好程序.
2. Java程序
这个程序先启动上述的C程序,再成立必要的衔接,以便同它“扳谈”.随后,它成立一个数据报套接字,用它“监督”大概“侦听”来自程序片的数据报包.
//: NameCollector.java // Extracts email names from datagrams and stores // them inside a file, using Java 1.02. import java.net.*; import java.io.*; import java.util.*; public class NameCollector { final static int COLLECTOR_PORT = 8080; final static int BUFFER_SIZE = 1000; byte[] buf = new byte[BUFFER_SIZE]; DatagramPacket dp = new DatagramPacket(buf, buf.length); // Can listen & send on the same socket: DatagramSocket socket; Process listmgr; PrintStream nameList; DataInputStream addResult; public NameCollector() { try { listmgr = Runtime.getRuntime().exec("listmgr.exe"); nameList = new PrintStream( new BufferedOutputStream( listmgr.getOutputStream())); addResult = new DataInputStream( new BufferedInputStream( listmgr.getInputStream())); } catch(IOException e) { System.err.println( "Cannot start listmgr.exe"); System.exit(1); } try { socket = new DatagramSocket(COLLECTOR_PORT); System.out.println( "NameCollector Server started"); while(true) { // Block until a datagram appears: socket.receive(dp); String rcvd = new String(dp.getData(), 0, 0, dp.getLength()); // Send to listmgr.exe standard input: nameList.println(rcvd.trim()); nameList.flush(); byte[] resultBuf = new byte[BUFFER_SIZE]; int byteCount = addResult.read(resultBuf); if(byteCount != -1) { String result = new String(resultBuf, 0).trim(); // Extract the address and port from // the received datagram to find out // where to send the reply: InetAddress senderAddress = dp.getAddress(); int senderPort = dp.getPort(); byte[] echoBuf = new byte[BUFFER_SIZE]; result.getBytes( 0, byteCount, echoBuf, 0); DatagramPacket echo = new DatagramPacket( echoBuf, echoBuf.length, senderAddress, senderPort); socket.send(echo); } else System.out.println( "Unexpected lack of result from " + "listmgr.exe"); } } catch(SocketException e) { System.err.println("Can't open socket"); System.exit(1); } catch(IOException e) { System.err.println("Communication error"); e.printStackTrace(); } } public static void main(String[] args) { new NameCollector(); } } ///:~
NameCollector中的第一个定义应当是大家所熟习的:选定端口,成立一个数据报包,然后成立指向一个DatagramSocket的句柄.接下来的三个定义负责与C程序的衔接:一个Process对象是C程序由Java程序启动之后返回的,并且那个Process对象产生了InputStream和OutputStream,辨别代表C程序的尺度输出和尺度输入.和Java IO一样,它们理所当然地需求“封装”起来,所以我们最后得到的是一个PrintStream和DataInputStream.
这个程序的全部工作都是在构建器内举行的.为启动C程序,需求获得当前的Runtime对象.我们用它调用exec(),再由后者返回Process对象.在Process对象中,大家可看到通过一简单的调用便可生成数据流:getOutputStream()和getInputStream().从这个时刻开始,我们需求考虑的全部事情就是将数据传给数据流nameList,并从addResult中获得后果.
和平常一样,我们将DatagramSocket同一个端口衔接到一同.在无限while循环中,程序会调用receive()——除非一个数据报到来,不然receive()会一同处于“堵塞”状况.数据报呈现今后,它的内容会提取到String rcvd里.我们首先将该字串两头的空格剔除(trim),再将其发给C程序.以下所示:
nameList.println(rcvd.trim());
之所以能这样编码,是因为Java的exec()答应我们拜候任何可履行模块,只要它能从尺度输入中读,并能向尺度输出中写.还有另一些方法可与非Java代码“扳谈”,这将在附录A中谈论.
从C程序中捕捉后果就显得略微麻烦一些.我们必须调用read(),并供应一个缓冲区,以便保存后果.read()的返回值是来自C程序的字节数.若这个值为-1,意味着某个地方呈现了问题.不然,我们就将resultBuf(后果缓冲区)转换成一个字串,然后一样排除多余的空格.随后,这个字串会象平常一样进入一个DatagramPacket,并传回当初发出恳求的那个一样的地址.注意发送方的地址也是我们接纳到的DatagramPacket的一部份.
记着固然C程序必须在Web服务器上编译,但Java程序的编译场所可以是肆意的.这是由于不管利用的是什么硬件平台和操作系统,编译得到的字节码都是一样的.就是Java的“跨平台”兼容本领.
以上是“<b>java服务器操纵</b>[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |
- ·上一篇文章:NameSender程序片
- ·下一篇文章:一个Web操纵
- ·中查找“<b>java服务器操纵</b>”更多相关内容
- ·中查找“<b>java服务器操纵</b>”更多相关内容
评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论