1、实现客户端上传图片
问题分析客户端
a、服务端点。
b、读取客户端已有的图片数据
c、通过Socket输出流将数据发给服务端
d、读取服务端反馈信息。
e、关闭
问题分析服务端
a、服务端服务,并监听窗口
b、获取客户端对象,并获取客户ip
c、读取客户端输入流数据
d、写入文件
e、用客户端输出流反馈信息
f、关流
packageorg.nagi.net;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*图片上传的服务器端
*@author dell
*
*/
publicclass PictureServer {
publicstaticvoid main(String[] args) {
try {
//建立一个服务器在12345端口监听
ServerSocket server = new ServerSocket(12345);
//连接客户端
Socket s =server.accept();
//得到输入流
InputStream in = s.getInputStream();
FileOutputStream out = new FileOutputStream("btbu.png");
int i = -1;
byte bs[] =newbyte[1024];
while((in.read(bs) != -1)){
out.write(bs, 0, i);
}
//得到输出流向客户端发送数据告诉已经上传成功
OutputStream sout = s.getOutputStream();
sout.write(("upload success !").getBytes());
sout.close();
in.close();
s.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
packageorg.nagi.net;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.OutputStream;
importjava.net.Socket;
importjava.net.UnknownHostException;
/**
*图片上传的客户端
*@author dell
*
*/
publicclass PictureClient {
publicstaticvoid main(String[] args) {
try {
//连接服务器 12345端口
Socket s = new Socket("127.0.0.1",12345);
//得到输出流
OutputStream out = s.getOutputStream();
FileInputStream fis = new FileInputStream("1.gif");
byte[] bs =newbyte[1024];
int line = -1;
while((line=fis.read(bs)) != -1){
out.write(bs, 0, line);
}
//告诉服务器已经发送完成
s.shutdownOutput();
out.close();
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
但是以上的出现一个问题——图片的上传只是一对一上传的,不能够多人上传;这个我们就需要解决多人上传图片的问题。
原因分析:服务器段存在有着局限性,当A客户端的连接到之后,被服务器端获得到,服务器就会执行相应的流程,这时客户端B连接上来只能在等待。原因是服务器在处理客户端A的请求的时候,在while循环一直是处于一个堵塞状态,没有机会处理客户端B的数据请求。
解决思想:为了使得每一个用户都可以并发的访问服务器,我们将每一个用户的请求都封装在一个线程里面。这样可以同时处理多个用户的请求。
例子代码:
packageorg.nagi.base;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*并发的处理多个用户提交上来的图片
*/
class PictureServer
{
publicstaticvoid main(String[] args)throws Exception
{
//创建服务,监听端口
@SuppressWarnings("resource")
ServerSocket ss=new ServerSocket(12345);
while (true)
{
//获取客户端对象
Socket s=ss.accept();
//只要出现一个客户一个新的线程立即执行
new Thread(new PicThread(s)).start();
}
}
}
//利用多线程实现并发上传
class PicThreadimplements Runnable{
private Sockets;
PicThread(Socket s){
this.s=s;
}
//复写Run的方法
publicvoid run()
{
//图片计数器保证提交的图片不会被覆盖
int count=1;
//获取客户端ip
String ip=s.getInetAddress().getHostAddress();
try
{
//通过客户端的读取流读取数据
InputStream in=s.getInputStream();
//文件保存路径
File dir =new File("C:\\picture\\a.jpg");
//文件名
File file=new File(dir,ip+".jpg");
//判断文件是否存在
while(file.exists()){
file=new File(dir,ip+"("+(count++)+").jpg");
}
//将数据写入到指定文件中
FileOutputStream fos=new FileOutputStream(file);
byte[] buf=newbyte[1024];
int len=0;
while ((len=in.read(buf))!=-1)
{
//向外写数据
fos.write(buf,0,len);
}
//将收到图片数据的信息返回给客户端
OutputStream out=s.getOutputStream();
out.write("上传成功!".getBytes());
fos.close();//关流
s.close();//关闭socket流
}
catch (Exception e)
{
//如果出现错误的话,就会打印出错误
e.printStackTrace();
}
}
}
客户端代码:
import java.io.*;
import java.net.*;
/**
* 客户端
* @author dell
*
*/
class PictureClient
{
public staticvoid main(String[] args) {
try{
//对传入的值进行判断
if(args.length!=1)
{
System.out.println("请选择上传一个图片文件!");
return;
}
File file=newFile(args[0]);
//对文件路径进行判断
if(!(file.exists()&&file.isFile()))
{
System.out.println("你上传的文件有问题!");
return;
}
//判断是否是图片文件
if(!file.getName().endsWith(".jpg"))
{
System.out.println("图片格式错误,请重新选择!");
return;
}
//对文件大小进行判断
if (file.length()>1024*1024*4)
{
System.out.println("你上传的文件过大!");
return;
}
//创建服务监听在本机12345端口上
Socket s=newSocket("127.0.0.1",12345);
//读取图片数据
FileInputStream fis=newFileInputStream(file);
//用Socket服务输出流写入数据
OutputStream out =s.getOutputStream();
//封装读取流
BufferedReader in=new BufferedReader(newInputStreamReader(s.getInputStream()));
byte[] buf=new byte[1024];
int len=0;
while ((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//结束标记,表示文件数据已经上传完了告诉服务器已经上传完成
s.shutdownOutput();
String info=in.readLine();//读取返回信息
System.out.println(info);
fis.close();//关流
s.close();//关闭socket
}catch (Exception e){
//如果出现了错误的话,打印出错误
e.printStackTrace();
}
}
}
2、客户并发的登陆
需求:实现客户端通过键盘录入用户名,服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx,已登陆;并在客户端显示xxx:欢迎光临。
如果用户不存在,在服务端显示xxx,尝试登陆;并在客户端显示xxx:该用户不存在。
最多就登录三次。
问题分析:用户存在打印出用户信息,如果不存在则打印出尝试登陆
解决方案:首页、服务器端可以并发的接收的客户端提交的信息,得到客户端信息之后,将得到的信息和用户信息表进行逐一比较,如果匹配成功之后,打印出用户信息;如果比配不成的话,服务端显示xxx,尝试登陆 ,向客户端打印,该用户不存在。
代码:
packageorg.nagi.net;
importjava.io.BufferedReader;
importjava.io.FileReader;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*客户登陆服务器端
*@author dell
*
*/
classUserLoginServer{
publicstaticvoid main(String [] args){
//创建服务,监听端口
try{
ServerSocket ss=new ServerSocket(12345);
while (true)
{
//获取客户端对象
Socket s=ss.accept();
//客户端执行线程
new Thread(new LoginThread(s)).start();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
*利用多线程实现并发登录
*@author dell
*
*/
class LoginThreadimplements Runnable{
private Sockets;
LoginThread(Socket s){
this.s=s;
}
publicvoid run(){
//获取客户端ip
String ip=s.getInetAddress().getHostAddress();
System.err.println("客户端用户:" + ip);//打印用户信息
try
{
for (int i=0;i<3 ;i++ )
{
//通过客户端的读取流读取数据
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream()));
//读取数据库中的数据,这里用文件来表示数据库
BufferedReader br=new BufferedReader(new FileReader("users.txt"));
String line=in.readLine();//读取客户端数据
if (line==null){//如果没有数据的话放回为空 读一行校验一行
break;//如果客户端没有发送数据,则跳出循环
}
String data=null;
boolean flag=false;//设置标记
//读取数据库中的用户数据
while ((data=br.readLine())!=null)
{
if (line.equals(data)){
flag=true;//如果用户存在,则将标记设为true
break;
}
}
//将数据写入到指定文件中
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
if (flag)//如果用户存在的话,打印出用户信息
{
System.out.println(line+",已登陆!");
out.println(line+":欢迎光临!");
break;
}
else
{
System.out.println(line+",尝试登陆!");
out.println(line+":用户名不存在!");
}
}
s.close();//关流
}
catch (Exception e)
{
//出现错误。并且打印
e.printStackTrace();
}
}
}
package org.nagi.net;
import java.io.*;
import java.net.*;
/**
*用户登陆客户端
*@author dell
*
*/
class UserLoginClient{
publicstaticvoidmain(String[] args) throws Exception
{
//在本地建立一个端口为12345服务器,
Socket s=new Socket("127.0.0.1",12345);
//从键盘得到标准的输出流
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//用Socket服务输出流写入数据 true:表示是PrintWriter自动flush()
PrintWriter out =new PrintWriter(s.getOutputStream(),true );
//接收服务器返回的信息
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
for(int i=0;i<3;i++)
{
line=br.readLine();//读取键盘录入
if (line==null)//输入端可能出现为空,保证没有空格键
{
break;//如果键盘没有输入,则直接结束
}
out.println(line);//将数据写入流中
String info=in.readLine();//读取返回信息
System.out.println(info);
if (info.contains("欢迎")) {
break;//如果登录成功,就跳出循环
}
}
br.close();//关流
s.close();//关闭socket
}
}