当前位置:七道奇文章资讯编程技术Java编程
日期: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编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • <b>hosts是什么 hosts文件在什么位置 若何改正hosts</b>
  • <b>在 Windows 8 中手动安装语言包</b>
  • <b>五个常见 PHP数据库问题</b>
  • Windows中Alt键的12个高效快速的利用本领介绍
  • <b>MySQL ORDER BY 的实现解析</b>
  • <b>详解MySQL存储历程参数有三种范例(in、out、inout)</b>
  • <b>Win8系统恢复出来经典的开始菜单的办法</b>
  • <b>Win8系统花屏怎么办 Win8系统花屏的办理办法</b>
  • <b>Windows 7系统下无线网卡安装</b>
  • <b>为什么 Linux不需求碎片整理</b>
  • <b>Windows 8中删除账户的几种办法(图)</b>
  • <b>教你如安在win7下配置路由器</b>
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .