- 浏览: 10375 次
最新评论
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 代码
import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; public class SimpleServer extends Thread{ private static final int DEFAULT_PORT = 4444; private static final String DEFAULT_FILE_NAME = "PyNet.pdf"; private Socket socket; public SimpleServer(Socket socket){ this.socket = socket; start(); } @Override public void run() { System.out.println("Connected from " + socket.getRemoteSocketAddress()); try { BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); String inputLine, outputLine; HandleInput handleInput = new HandleInput(); outputLine = handleInput.handle(null); out.println(outputLine); while((inputLine = in.readLine()) != null){ outputLine = handleInput.handle(inputLine); out.println(outputLine); out.flush(); if(outputLine.equals("bye")) break; if(outputLine.equals("password:valid")){ //prepare for the transmission of the file Thread.sleep(2000); InputStream fileInput = new FileInputStream(new File(DEFAULT_FILE_NAME)); OutputStream fileOutput = new DataOutputStream( new BufferedOutputStream(socket.getOutputStream())); byte[] buf = new byte[2048]; //transmit the file int num = fileInput.read(buf); while(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(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private class HandleInput{ private Map userInfo = new HashMap(); private String username = ""; private String password = ""; public HandleInput(){ userInfo.put("yangsq", "yangsq"); userInfo.put("abc", "abc"); userInfo.put("123", "123"); } public String handle(String input){ String output = ""; if(input == null) output = "Hi"; else if(input.startsWith("username")){ username = input.split(":")[1]; if(userInfo.containsKey(username)) output = "username:valid"; else output = "username:invalid"; }else if(input.startsWith("password")){ password = input.split(":")[1]; if(userInfo.get(username).equals(password)) output = "password:valid"; else output = "password:invalid"; }else if(input.equals("bye")){ output = "bye"; } return output; } } public static void main(String[] args) { int port = DEFAULT_PORT; if(args.length > 0){ port = Integer.parseInt(args[0]); } try { ServerSocket serverSocket = new ServerSocket(port); System.out.println("Server Started"); try { while(true){ Socket theSocket = serverSocket.accept(); try { new SimpleServer(theSocket); } catch (Exception e) { e.printStackTrace(); theSocket.close(); } } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { if(serverSocket != null) serverSocket.close(); } } catch (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 代码
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.net.Socket; import java.net.UnknownHostException; public class SimpleClient { private static final int DEFAULT_PORT = 4444; private static final String DEFAULT_HOST = "localhost"; public static void main(String[] args) { String host = DEFAULT_HOST; int port = DEFAULT_PORT; if(args.length > 0){ host = args[0]; } if(args.length >1 ){ port = Integer.parseInt(args[1]); } Socket theSocket = null; PrintWriter out = null; BufferedReader in = null, userIn = null; try { theSocket = new Socket(host, port); in = new BufferedReader( new InputStreamReader(theSocket.getInputStream())); out = new PrintWriter(theSocket.getOutputStream()); userIn = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Connected to the simple file server"); String fromUser, fromServer; while((fromServer = in.readLine()) != null){ if(fromServer.equals("bye")) break; else if(fromServer.equals("Hi")){ System.out.println("Do you want to get the 'PyNet.pdf' file?(y/n):"); fromUser = userIn.readLine(); if(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 }else break; }else if(fromServer.startsWith("username")){ if(fromServer.split(":")[1].equals("valid")){ System.out.println("Please input your password:"); fromUser = userIn.readLine(); out.println("password:" + fromUser); out.flush(); }else{ System.out.println("Please input your username:"); fromUser = userIn.readLine(); out.println("username:" + fromUser); out.flush(); } }else if(fromServer.startsWith("password")){ if(fromServer.split(":")[1].equals("valid")){ System.out.println("Downloading..."); //prepare for the receiving File newFile = new File("new.pdf"); newFile.createNewFile(); RandomAccessFile raf = new RandomAccessFile(newFile, "rw"); InputStream fileInput = new DataInputStream( new BufferedInputStream(theSocket.getInputStream())); byte[] buf = new byte[2048]; //receiving int num = fileInput.read(buf); while(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"); break; }else{ 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(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (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端就是在那塞着,这个问题困扰了我半天,呵呵。
发表评论
-
《ASCE1885的网络编程》の套接字select模型
2012-01-20 00:44 745《ASCE1885的网络编程》 ... -
Winsocket入门教程二:非阻塞式服务器和客户端程序(TCP)
2012-01-20 00:44 710Winsocket入门教程二:非阻 ... -
C#线程池
2012-01-20 00:44 567C#线程池 2011年06月23日 ... -
linux TCP
2012-01-20 00:44 732linux TCP 2011年05月16日 Linux下 ... -
通用(任何android机型)Root教程(完整版!附砖机自救方法)转自安卓网
2012-01-17 01:01 900通用(任何android机型)Root ... -
无法安装或运行此应用程序。该应用程序要求首先在“全局程序集缓存(GAC)”中安装程序集stdole版本7.0.3300.0
2012-01-17 01:01 1504无法安装或运行此应用程序。该应用程序要求首先在“全局程序集缓存 ... -
Android开发之--adb shell 命令大全
2012-01-17 01:01 757Android开发之--adb shell 命令大全 201 ... -
慢慢研究
2012-01-17 01:01 556慢慢研究 2011年12月24日 ... -
系统安全-使你的电脑固若金汤,百毒不侵
2012-01-17 01:01 592系统安全-使你的电脑固 ... -
C++ socket编程基础(理论篇)[转]
2012-01-15 19:44 658C++ socket编程基础(理论 ... -
C# Socket网络编程学习(1-->3)
2012-01-15 19:43 711C# Socket网络编程学习(1-- ... -
C# Socket多线程编程实例
2012-01-15 19:43 778C# Socket多线程编程实例 ... -
基于C#的Socket开发快速入门
2012-01-15 19:43 512基于C#的Socket开发快速 ...
相关推荐
实现了C/S架构的Socket多线程IO通信。 实现了Socket长连接的TCP网络通信。 基于Java GUI的人机交互界面,单个服务器(Server)持续处理客户端信息并统一转发,多个客户端(Client)可以同时持续与服务器建立连接并相互...
实现了C/S架构的Socket多线程IO通信。 实现了Socket长连接的TCP网络通信。 基于Java GUI的人机交互界面,单个服务器(Server)持续处理客户端信息并统一转发,多个客户端(Client)可以同时持续与服务器建立连接并相互...
利用Socket编程实现C/S应用。其中,Client端为GUI程序,用于提供界面输入两个数,并有1个“发送”按钮,另外还有一个 TextField用于显示传来的计算结果;Server端用于监听连接请求、计算发送过来的两数的和、送回...
JICQ是用JAVA语言编写的一个基于客户机/服务器(C/S)模式的局域短信实时通信工具系统,系统采用了Microsoft公司的SQL Server 2000作为后台数据库,系统通过JDBC访问数据库。系统分为服务器程序和客户程序两部分,...
1、本项目则是使用Java实现TCP的Socket网络通信,包含C/S软件架构的程序设计,偏向实践,更加有趣! 2、实现简单有趣的“创意”聊天机器人。 3、建立通信规则: Server和Client之间需要约定相同的规则,保证正常通信...
采用TCP SOCKET技术编写C/S模式的聊天室软件,聊天室具有群聊、私聊等功能,支持多个连接,支持消息边界,
一个基于tcp连接的socket例子,适合初学者.有画面,数据结构的部分实现没有用JAVA自己封装的.自己写了一个链表.
服务器端程序创建一个监听Socket对象以等待客户端连接,当有客户端连接时,使用一个新的线程处理该客户端连接,同时循环读取客户端发送的消息并发送给其他连接了服务器的客户端。用户输入的消息通过服务器传递给所有...
用于实现单一的即时通讯、文件共享的软件实在太少,而且,它们中大部分都是绝对的C/S模式,我们决定开发一个专用于实现两台计算机之间即时通讯的软件,以方便两台计算机之间信息的交流。本软件属于点对点连接的,...
晕有个带密码两个好使的
Swing界面 用Socket进行通信 客户端服务器端分离 用多线程实现一对多连接 内附数据库备份
1)设计程序,分别构建通信的两端:服务器端和客户端应用程序,套接字类型为面向连接的Socket,自己构建双方的应答模式,实现双方的数据的发送和接收(S发给C,C发给S)。 2)服务端程序能响应单个或任意多个客户端...
自己写的一个网络白板程序,有客户端和服务器端,...网络白板是非常适合初学者研究的一个项目,对于是用socket,了解s/c机制有些帮助。我的代码也写得十分简单,功能也比较齐全,而且这个是福利资源,大家快来下!
本软件是采用sun公司开发提供的java语言制作的,是基于C/S模型的网上聊天室。这个系统分为两个部分,服务端和客户端。服务端的工作主要是来监听和接收来自客户端的请求,然后处理客户端发来的消息,并通知客户端。...
项目描述: 属于用JAVA实现基于C/S模式的聊天室系统,该聊天室分为客户端,服务器端和聊天界面三个模块。服务器端实现侦听来自客户端的请求,并显示在线人数。客户端实现登陆,检查,注册,功能。聊天界面实现了显示...
使用Socket实现网上聊天室,要求基于TCP或UDP协议,用户可以通过客户端连接到服务器端并进行聊天,聊天时可以启动多个客户端;服务器启动后,接收客户端发来的用户名和验证信息,验证通过则可以加入聊天室,当客户...
它基于C/S模式,通过Socket连接,利用MySQL数据库服务器、JDBC数据库连接等技术,完成了远程监测分析系统的开发。该远程监控平台主要用于一般中小局域网或虚拟局域网,通过监控端对监控端进行监控和管理,即使不出门,...
基于C的面向连接的socket编程模型 1. 点对点通信功能 实现网络点对点通讯程序的关键步骤就是实现信息在网络中的发送和接收。数据接收 使用的是Socket,数据发送使用的是NetworkStream。 1.1利用Socket来接收信息 ...
基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...
任务概述 本项任务要开发一款P2P文件传输软件,该软件可以在局域网和互连上使用,具有文件传输,断点续传,多线程连接等功能。