黑马程序员——>第二十四天<网络编程(TCP-Tomcat)>

-------android培训java培训、期待与您交流-------

01网络编程(TCP-上传图片)


需求:上传图片。
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。

import java.io.*;
import java.net.*;
class  PicClient
{
 public static void main(String[] args)throws Exception 
 {
  Socket s = new Socket("192.168.1.254",10007);

  FileInputStream fis = new FileInputStream("c:\\1.bmp");  // 读数据   肯定是字节流

  OutputStream out = s.getOutputStream();

  byte[] buf = new byte[1024];

  int len = 0;

  while((len=fis.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }

  //告诉服务端数据已写完
  s.shutdownOutput();

  InputStream in = s.getInputStream();   //接收服务端发来的信息

  byte[] bufIn = new byte[1024];

  int num = in.read(bufIn);
  System.out.println(new String(bufIn,0,num));

  fis.close();
  s.close();
 }
}

服务端

class  PicServer
{
 public static void main(String[] args) throws Exception
 {
  ServerSocket ss = new ServerSocket(10007);

  Socket s = ss.accept();   //拿到Socket对象

  InputStream in = s.getInputStream();  //读取Socket流中的数据

  FileOutputStream fos = new FileOutputStream("server.bmp");   // 将数据写到一个文件中去

  byte[] buf = new byte[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();

  ss.close();
 }
}

02网络编程(TCP-客户端并发上传图片)


需求:上传图片。
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。

 

import java.io.*;
import java.net.*;
class  PicClient
{
 public static void main(String[] args)throws Exception 
 {
//通过主函数传值的形式
  if(args.length!=1) // =1就是往里边传了一个参数   !=1就是传入出错
  {
   System.out.println("请选择一个jpg格式的图片");
   return ;
  }

 


  File file = new File(args[0]);  //传路径进来   把路径封装成file对象
  if(!(file.exists() && file.isFile()))  //不存在  与  不是文件
  {
   System.out.println("该文件有问题,要么补存在,要么不是文件");
   return ;

  }

  if(!file.getName().endsWith(".jpg"))
  {
   System.out.println("图片格式错误,请重新选择");
   return ;
  }

  if(file.length()>1024*1024*5)
  {
   System.out.println("文件过大,没安好心");
   return ;
  }
  

 

  Socket s = new Socket("192.168.1.254",10007);     // 建立连接  

  FileInputStream fis = new FileInputStream(file);    // 读取文件信息

  OutputStream out = s.getOutputStream();

  byte[] buf = new byte[1024];

  int len = 0;

  while((len=fis.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }

  //告诉服务端数据已写完
  s.shutdownOutput();

  InputStream in = s.getInputStream();

  byte[] bufIn = new byte[1024];

  int num = in.read(bufIn);
  System.out.println(new String(bufIn,0,num));

  fis.close();
  s.close();
 }
}


服务端

这个服务端有个局限性。当A客户端连接上以后。被服务端获取到。服务端执行具体流程。
这时B客户端连接,只有等待。
因为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法。所以
暂时获取不到B客户端对象。

那么为了可以让多个客户端同时并发访问服务端。
那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。

 

如何定义线程呢?

只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。

class PicThread implements Runnable
{

 private Socket s;  //客户端
 PicThread(Socket s)
 {
  this.s = s;
 }
 public void run()
 {

  int count = 1;   //搞一个计数器 用来 将你添加的图片进行编号 让其不至于覆盖
//若定义成  成员  多个数据共享这一个数据,
  String ip  = s.getInetAddress().getHostAddress();
  try
  {
   System.out.println(ip+"....connected");

   InputStream in = s.getInputStream();
//为了不让后添加的图片不覆盖前面的图片    就拿ip地址来命名
   File dir =  new File("d:\\pic");

   File file = new File(dir,ip+"("+(count)+")"+".jpg");//192.168.1.254(1).jpg

   while(file.exists())                   //判断上面的文件名是否存在   若存在 就往下执行 再new一个
    file = new File(dir,ip+"("+(count++)+")"+".jpg");

   FileOutputStream fos = new FileOutputStream(file);

   byte[] buf = new byte[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();
  }
  catch (Exception e)
  {
   throw new RuntimeException(ip+"上传失败");
  }
 }
}

 

class  PicServer
{
 public static void main(String[] args) throws Exception       //主函数一执行  会有一个主线程
 {
  ServerSocket ss = new ServerSocket(10007);         //紧跟着建立服务

  while(true)                                                             // 循环建立线程
  {
   Socket s = ss.accept();                                   //while 进来后就开始等待   主线程在等待
   //  若真进来一个a客户端进来的话就往下执行,
   new Thread(new PicThread(s)).start(); // a客户端被Thread对象封装进去了  单独开了一个线程
/*这个时候有俩线程  一个主线程  一个a客户端所在线程 两个线程可以同时执行   a客户端开始跑起来,主线程还能执行,while 进来后就开始等待   主线程在等待  这个时候b就连进来了,获取到后accept();  就new一个b的线程   这个时候a还在跑,b也可以跟着跑起来。
   服务器得弄成多线程,*/
  }

  //ss.close();
 }
}



要将客户端封装在线程当中    服务端开启多个线程来处理  客户端的并发请求访问

03网络编程(TCP-客户端并发登陆)


客户端通过键盘录入用户名。
服务端对这个用户名进行校验。

如果该用户存在,在服务端显示xxx,已登陆。
并在客户端显示 xxx,欢迎光临。

如果该用户不存在,在服务端显示xxx,尝试登陆。
并在客户端显示 xxx,该用户不存在。

最多就登录三次。  若登陆一次就成功那就结束,  要有个用户名列表(通常是数据库)

import java.io.*;
import java.net.*;


class  LoginClient
{
 public static void main(String[] args) throws Exception
 {
  Socket s = new Socket("192.168.1.254",10008);

  BufferedReader bufr =   //读取键盘录入     
   new BufferedReader(new InputStreamReader(System.in));

  PrintWriter out = new PrintWriter(s.getOutputStream(),true); //将数据都读出来 发到服务端去

  BufferedReader bufIn =   //发完后服务端要给你反馈信息  要有读的动作 读Socket流
   new BufferedReader(new InputStreamReader(s.getInputStream()));

//前面的都是while循环 ,但是这个要求客户端最多只发送三次
  for(int x=0; x<3; x++)  //限定次数
  {
   String line = bufr.readLine();  //键盘录入
   if(line==null)
    break;
   out.println(line);

   String info = bufIn.readLine();  //服务端的反馈信息
   System.out.println("info:"+info);
   if(info.contains("欢迎")) // 包含欢迎字样
    break;

  }

  bufr.close();
  s.close();
 }
}


class UserThread implements Runnable
{//每个客户端分配线程的代码
 private Socket s;   //客户端不明确   往里传
 UserThread(Socket s)
 {
  this.s = s;
 }
 public void run()
 {
  String ip = s.getInetAddress().getHostAddress();  //  过来的每个用户都有ip
  System.out.println(ip+"....connected");
  try//进行校验
  {
   for(int x=0; x<3; x++)
   {
    BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));//先获取到客户端发过来的用户名         读Socket流

    String name = bufIn.readLine();  //用户名  不需要循环  因为你就 发过来一个名字
    if(name==null)
     break;
//服务端注册用户名列表存一个文件里了   要读这个文件
    BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));读注册用户文件

    PrintWriter out = new PrintWriter(s.getOutputStream(),true);

    String line = null;
//因为要根据循环后的结果来判断  必然要在while外判断
    boolean flag = false;   //就要定义一个标记   要用标记来记录下这个结果
    while((line=bufr.readLine())!=null)   //读一行校验一次
    {
     if(line.equals(name))   //这个若不满足 就回过头去读第二行   
     {
      flag = true;//满足就为真   说明这个用户在
      break;  //找着后就没必要往下找了   所以直接break
     }    
    }
    
    if(flag)     //根据循环后 的结果来判断    如果真
    {
     System.out.println(name+",已登录");
     out.println(name+",欢迎光临"); // 因为要写点东西  所以上面就搞一个流
     break;//这个满足后就不需要循环校验了  直接break
    }
    else
    {
     System.out.println(name+",尝试登录");
     out.println(name+",用户名不存在");
    }


   }
   s.close();
  }
  catch (Exception e)
  {  //处理不好的   抛出去
   throw new RuntimeException(ip+"校验失败");
  }
 }
}
class  LoginServer
{
 public static void main(String[] args) throws Exception
 {
  ServerSocket ss = new ServerSocket(10008);

  while(true)
  {
   Socket s = ss.accept();

   new Thread(new UserThread(s)).start(); // new一个线程
  }
 }
}

04络编程(浏览器客户端—自定义服务端)

客户端  服务端 无非就是一个基于网络的程序而已
 浏览器就是标准的客户端,


演示客户端和服务端。

1,
客户端:浏览器 (telnet)
服务端:自定义。

2,
客户端:浏览器。
服务端:Tomcat服务器。

3,
客户端:自定义。(图形界面)
服务端:Tomcat服务器。

 


05网络编程(自定义浏览器-Tomcat服务端)

import java.net.*;
import java.io.*;
class ServerDemo //自定义服务端
{
 public static void main(String[] args) throws Exception
 {
  ServerSocket ss = new ServerSocket(11000);

  Socket s = ss.accept();
  System.out.println(s.getInetAddress().getHostAddress());
/*浏览器给服务端发了什么数据  才能请求到 My web那个资源

  验证那个内容

发送的是http的请求消息头
   浏览器和服务端虽然是不同厂商制作的  但是都遵从一些国际标准化的协议和规则
 底层都是tcp 应用层有个http协议这是一个公共的传输规则*/
  InputStream in = s.getInputStream(); //获取浏览器发送的请求信息

  byte[] buf = new byte[1024];

  int len = in.read(buf);

  System.out.println(new String(buf,0,len));

 

  PrintWriter out = new PrintWriter(s.getOutputStream(),true);//往客户端打个数据就成
          // 然后再给浏览器返回信息
  out.println("<font color='red' size='7'>客户端你好</font>");

  s.close();

  ss.close();
 }
}


这个称之为http的请求消息头
http://192.168.1.254:11000/myweb/demo.html  
协议   主机名      端口号  资源路径   资源demo.html
GET /myweb/demo.html HTTP/1.1                                        请求行
Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, i
mage/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application
/msword, application/QVOD, application/QVOD,
Accept-Language: zh-cn   支持语言 简体中文版
Accept-Encoding: gzip, deflate  支持封装形式
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0
.50727)              用户信息
Host: 192.168.1.254:11000             主机   端口
Connection: Keep-Alive                连接   保持  存活  保持连接  连接存在
                       这里有一行空行              这是订的标准

                        然后下面是请求数据体
  请求数据体和请求消息头之间必须留一行空行隔开       代表  哪段数据是头  哪段数据时体

客户端向服务器发送一个get请求
Accept  能接受的数据类型
 gzip
在新浪那一端要给你的数据进行压缩,到你这边解压缩  提高了传输效率   支持gzip压缩

deflate

import java.io.*;
import java.net.*;

class MyIE 
{
 public static void main(String[] args)throws Exception 
 {
  Socket s = new Socket("192.168.1.254",8080);//因为不是图形化界面就写死
  
  PrintWriter out = new PrintWriter(s.getOutputStream(),true); // 给服务器发数据

  out.println("GET /myweb/demo.html HTTP/1.1");
  out.println("Accept: */*");
  out.println("Accept-Language: zh-cn");
  out.println("Host: 192.168.1.254:11000");
  out.println("Connection: closed");   

  out.println();
  out.println();
//到这一步就将数据发给服务器了
  BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
//读服务器返回来的数据
  String line = null;

  while((line=bufr.readLine())!=null)
  {
   System.out.println(line);
  }

  s.close();
 }
}


06网络编程(URL-URLConnection)

类 URL代表一个统一资源定位符,它是指向互联网“资源”的指针


URL(String spec)
 根据String表示形式创建URL对象

URL(Sring protocol,String host,int port,String file)  协议  主机  端口 文件

import java.net.*;
class URLDemo 
{
 public static void main(String[] args) throws MalformedURLException
 {
  URL url = new URL("http://192.168.1.254/myweb/demo.html?name=haha&age=30");
//?进行分隔   &进行多信息连接   信息都是以键值对出现

  System.out.println("getProtocol() :"+url.getProtocol());
  System.out.println("getHost() :"+url.getHost());
  System.out.println("getPort() :"+url.getPort());
  System.out.println("getPath() :"+url.getPath());
  System.out.println("getFile() :"+url.getFile());
  System.out.println("getQuery() :"+url.getQuery());

  /*int port = getPort();
  if(port==-1)
   port = 80;

  getPort()==-1
 
 }
}




 String getFile()                               路径加后面的参数
          获取此 URL 的文件名。
 String getHost()
          获取此 URL 的主机名(如果适用)。
 String getPath()                             路径
          获取此 URL 的路径部分。
 int getPort()
          获取此 URL 的端口号。
 String getProtocol()
          获取此 URL 的协议名称。
 String getQuery()                         拿后面的参数
          获取此 URL 的查询部

面试时  要你说出几个异常   能够说出来

07网络编程(小知识点)

Socket() 
 不需要传递主机和端口的空参数构造函数  他会用connect(SocketAddress endpoint)方法去连接
connect(SocketAddress endpoint)

InetAddress  封装的是ip地址
InetSocketAddress  封装的是 ip地址+端口
SocketAddress 封装的是 端口

 

ServerSocket(int port,int backlog)  端口   队列的最大长度  就是最多可以同时连接多少

-------android培训java培训、期待与您交流-------

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值