java socket连接c/s (转)

java socket连接c/s (转)
2010年07月08日
  用java实现的简单Server/Client文件传输关键字: java server client
  用一种编程语言实现一个简单的Server/Client程序; 该程序的主要功能是利用Client从Server端下载一个文件; 在下载之前,需要有一定的用户身份验证机制(说白了就是先输入以下用户名和密码); Server应该是多线程机制的,即为每个Client请求Server都要有一个线程去处理,而不是所有的Client都是一个Server线程处理。 ok,这就是需求,单从编程角度来讲,题目不难,单老师说过一句话,我觉得非常有道理,“看一万个程序,不如自己亲自写一个程序,写一万个程序,不如努力写一个好程序”,所以我就利用十一假期的最后两天,完成了这样一个作业,当然大部分时间还是画在了学习不太熟悉的python上。在这里,还要感谢一下CSDN上“wumingabc的专栏”的一篇blog,参考了他的一些代码。
  处理流程:
  server启动,监听client请求; client启动; server监听到client,发送“Hi”; client收到“Hi” client要求用户输入用户名; 用户输入用户名(如yangsq),发送到服务器(形式为“username:yangsq”); 服务器验证是否存在这样一个用户,如果有到step 8,否则转到5; client用求用户输入密码(如123456),发送到服务器(形式为“password:123456”); 服务器验证密码是否正确,不正确转到step 8,正确开始传输文件(为了简单,文件预先指定好); client收到文件,结束后发送“bye”;同时server端收到“bye”后结束线程。 服务器端:
  java 代码
  [b]import[/b] java.io.BufferedOutputStream; [b]import[/b] java.io.BufferedReader; [b]import[/b] java.io.BufferedWriter; [b]import[/b] java.io.DataOutputStream; [b]import[/b] java.io.File; [b]import[/b] java.io.FileInputStream; [b]import[/b] java.io.IOException; [b]import[/b] java.io.InputStream; [b]import[/b] java.io.InputStreamReader; [b]import[/b] java.io.OutputStream; [b]import[/b] java.io.OutputStreamWriter; [b]import[/b] java.io.PrintWriter; [b]import[/b] java.net.ServerSocket; [b]import[/b] java.net.Socket; [b]import[/b] java.util.HashMap; [b]import[/b] java.util.Map; [b]public[/b] [b]class[/b] SimpleServer [b]extends[/b] Thread{ [b]private[/b] [b]static[/b] [b]final[/b] [b]int[/b] DEFAULT_PORT = 4444; [b]private[/b] [b]static[/b] [b]final[/b] String DEFAULT_FILE_NAME = "PyNet.pdf"; [b]private[/b] Socket socket; [b]public[/b] SimpleServer(Socket socket){ [b]this[/b].socket = socket; start(); } @Override [b]public[/b] [b]void[/b] run() { System.out.println("Connected from " + socket.getRemoteSocketAddress()); [b]try[/b] { BufferedReader in = [b]new[/b] BufferedReader( [b]new[/b] InputStreamReader(socket.getInputStream())); PrintWriter out = [b]new[/b] PrintWriter( [b]new[/b] BufferedWriter([b]new[/b] OutputStreamWriter(socket.getOutputStream())), [b]true[/b]); String inputLine, outputLine; HandleInput handleInput = [b]new[/b] HandleInput(); outputLine = handleInput.handle([b]null[/b]); out.println(outputLine); [b]while[/b]((inputLine = in.readLine()) != [b]null[/b]){ outputLine = handleInput.handle(inputLine); out.println(outputLine); out.flush(); [b]if[/b](outputLine.equals("bye")) [b]break[/b]; [b]if[/b](outputLine.equals("password:valid")){ //prepare for the transmission of the file Thread.sleep(2000); InputStream fileInput = [b]new[/b] FileInputStream([b]new[/b] File(DEFAULT_FILE_NAME)); OutputStream fileOutput = [b]new[/b] DataOutputStream( [b]new[/b] BufferedOutputStream(socket.getOutputStream())); [b]byte[/b][] buf = [b]new[/b] [b]byte[/b][2048]; //transmit the file [b]int[/b] num = fileInput.read(buf); [b]while[/b](num != -1){ fileOutput.write(buf, 0, num); fileOutput.flush(); num = fileInput.read(buf); } fileInput.close(); fileOutput.close(); } } in.close(); out.close(); System.out.println("Disconnected from " + socket.getRemoteSocketAddress()); socket.close(); } [b]catch[/b] (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } [b]catch[/b] (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } [b]private[/b] [b]class[/b] HandleInput{ [b]private[/b] Map userInfo = [b]new[/b] HashMap(); [b]private[/b] String username = ""; [b]private[/b] String password = ""; [b]public[/b] HandleInput(){ userInfo.put("yangsq", "yangsq"); userInfo.put("abc", "abc"); userInfo.put("123", "123"); } [b]public[/b] String handle(String input){ String output = ""; [b]if[/b](input == [b]null[/b]) output = "Hi"; [b]else[/b] [b]if[/b](input.startsWith("username")){ username = input.split(":")[1]; [b]if[/b](userInfo.containsKey(username)) output = "username:valid"; [b]else[/b] output = "username:invalid"; }[b]else[/b] [b]if[/b](input.startsWith("password")){ password = input.split(":")[1]; [b]if[/b](userInfo.get(username).equals(password)) output = "password:valid"; [b]else[/b] output = "password:invalid"; }[b]else[/b] [b]if[/b](input.equals("bye")){ output = "bye"; } [b]return[/b] output; } } [b]public[/b] [b]static[/b] [b]void[/b] main(String[] args) { [b]int[/b] port = DEFAULT_PORT; [b]if[/b](args.length > 0){ port = Integer.parseInt(args[0]); } [b]try[/b] { ServerSocket serverSocket = [b]new[/b] ServerSocket(port); System.out.println("Server Started"); [b]try[/b] { [b]while[/b]([b]true[/b]){ Socket theSocket = serverSocket.accept(); [b]try[/b] { [b]new[/b] SimpleServer(theSocket); } [b]catch[/b] (Exception e) { e.printStackTrace(); theSocket.close(); } } } [b]catch[/b] (Exception e) { // TODO: handle exception e.printStackTrace(); } [b]finally[/b] { [b]if[/b](serverSocket != [b]null[/b]) serverSocket.close(); } } [b]catch[/b] (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
  说明:
  main函数是Server的启动点,在这里我们建立了一个ServerSocket的实例,这个类是java中专门进行Server端编程的,它可以进行很多的复杂配置,这里知识把它建立在了一个端口之上(line-125),然后为请求返回socket(line-131)。 SimpleServer类继承了Thread,也就是说,我的想法是为每一个Client请求,都有一个SimpleServer去处理。这是怎样实现的呢?看line-128到line-136,这里ServerSocket的实例在端口4444进行监听,只要有一个请求,就new一个SimpleServer去处理(如果没有请求,程序就会阻塞在ServerSocket的accept方法上line-129) 既然SimpleServer继承了Thread,那么它的最重要的方法就是run(line-29),可以看到,在new SimpleServer的时候就启动了它的run方法。 SimpleServer的主要处理流程在line-42到line-67,为了更清晰,把其中的用户身份验证提出来组成一个内部类HandleInput。 负责文件传输的是line-48到line-66,也即clien的密码正确后开始。这里需要说明的是流的实现,与用户交互的时候我们用的是New IO,他们是面向字节(1字节=2byte)的,这很合适,因为我们的用户信息都是字节的(简单的说就是面向asc字符的),所以这里我们就用了readline和println方法(这两个都是Reader和Writer的方法);但是我们要传输的是一个二进制文件(说白了就是面向byte的),所以用New IO就不合适了,所以转向了InputStream(读入文件)和OutputStream(把文件通过socket写出)。 客户端:
  java 代码
  [b]import[/b] java.io.BufferedInputStream; [b]import[/b] java.io.BufferedReader; [b]import[/b] java.io.DataInputStream; [b]import[/b] java.io.File; [b]import[/b] java.io.IOException; [b]import[/b] java.io.InputStream; [b]import[/b] java.io.InputStreamReader; [b]import[/b] java.io.PrintWriter; [b]import[/b] java.io.RandomAccessFile; [b]import[/b] java.net.Socket; [b]import[/b] java.net.UnknownHostException; [b]public[/b] [b]class[/b] SimpleClient { [b]private[/b] [b]static[/b] [b]final[/b] [b]int[/b] DEFAULT_PORT = 4444; [b]private[/b] [b]static[/b] [b]final[/b] String DEFAULT_HOST = "localhost"; [b]public[/b] [b]static[/b] [b]void[/b] main(String[] args) { String host = DEFAULT_HOST; [b]int[/b] port = DEFAULT_PORT; [b]if[/b](args.length > 0){ host = args[0]; } [b]if[/b](args.length >1 ){ port = Integer.parseInt(args[1]); } Socket theSocket = [b]null[/b]; PrintWriter out = [b]null[/b]; BufferedReader in = [b]null[/b], userIn = [b]null[/b]; [b]try[/b] { theSocket = [b]new[/b] Socket(host, port); in = [b]new[/b] BufferedReader( [b]new[/b] InputStreamReader(theSocket.getInputStream())); out = [b]new[/b] PrintWriter(theSocket.getOutputStream()); userIn = [b]new[/b] BufferedReader( [b]new[/b] InputStreamReader(System.in)); System.out.println("Connected to the simple file server"); String fromUser, fromServer; [b]while[/b]((fromServer = in.readLine()) != [b]null[/b]){ [b]if[/b](fromServer.equals("bye")) [b]break[/b]; [b]else[/b] [b]if[/b](fromServer.equals("Hi")){ System.out.println("Do you want to get the 'PyNet.pdf' file?(y/n):"); fromUser = userIn.readLine(); [b]if[/b](fromUser.equals("y")){ System.out.println("Please input your username:"); fromUser = userIn.readLine(); out.println("username:" + fromUser); out.flush();//notice: if this sentence is lost, the info will not arrive at server side }[b]else[/b] [b]break[/b]; }[b]else[/b] [b]if[/b](fromServer.startsWith("username")){ [b]if[/b](fromServer.split(":")[1].equals("valid")){ System.out.println("Please input your password:"); fromUser = userIn.readLine(); out.println("password:" + fromUser); out.flush(); }[b]else[/b]{ System.out.println("Please input your username:"); fromUser = userIn.readLine(); out.println("username:" + fromUser); out.flush(); } }[b]else[/b] [b]if[/b](fromServer.startsWith("password")){ [b]if[/b](fromServer.split(":")[1].equals("valid")){ System.out.println("Downloading..."); //prepare for the receiving File newFile = [b]new[/b] File("new.pdf"); newFile.createNewFile(); RandomAccessFile raf = [b]new[/b] RandomAccessFile(newFile, "rw"); InputStream fileInput = [b]new[/b] DataInputStream( [b]new[/b] BufferedInputStream(theSocket.getInputStream())); [b]byte[/b][] buf = [b]new[/b] [b]byte[/b][2048]; //receiving [b]int[/b] num = fileInput.read(buf); [b]while[/b](num != -1){ raf.write(buf, 0, num); raf.skipBytes(num); num = fileInput.read(buf); } in.close(); raf.close(); System.out.println("File download is finished"); [b]break[/b]; }[b]else[/b]{ System.out.println("Please input your password:"); fromUser = userIn.readLine(); out.println("password:" + fromUser); out.flush(); } } } out.println("bye"); out.flush(); out.close(); in.close(); userIn.close(); theSocket.close(); } [b]catch[/b] (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } [b]catch[/b] (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
  这个比较简单,除了用户交互外,最核心的就是line-71到line-94这段处理文件下载的了,当SimpleClient收到服务器的“password:valid"就表示用户身份验证通过,可以执行文件下载了。这部分也是混合使用了New IO和Old IO,原因和上边解释的一样。
  这里还要强调一点的是在网络编程的时候,println以后,一定要flush以下。为什么呢?学过网络的人都知道,当一个package太小是,网络并不会把它发出去,而是等到足够大时。我在实际测试时,就忘记了在println后写flush,结果这边明明已经out出了,但Server端就是在那塞着,这个问题困扰了我半天,呵呵。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值