黑马程序员——17Java网络编程2


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

1,多线程上传图片。
 
     import java.io.*;
      import java.net.*;
      //定义客户端
      class PicClient{
              public static void main(String[] args)throws Exception{
                      //在客户端对上传文件检查,失败就不用上传。
                      if(args.length!=1){
                              System.out.println("请选择一个jpg格式的图片");
                              return;
                      }
                      File file=new File(args[0]);
                      if(!(file.exists()&&file.isFile())){
                              System.out.println("该文件不存在或者不是文件,上传失败");
                              return;
                      }
                      if(!(file.getName().endsWith(".jpg"))) {
                              System.out.println("文件不是jpg格式,上传失败");
                              return;
                      }
                     if(file.length()>1024*1024*5){
                              System.out.println("文件超过5M,上传失败");
                              return;
                      }
                      Socket s=new Socket("192.168.1.7",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();
             }
      }
      //服务服务端,为了让多个客户端同时并发访问服务端,这是需要报服务器做成多线程。把客户端要在服务端执行的代码放入Run方法。
    class PicThread implements Runnable{
        private Socket s;
            PicThread(Socket s){
                    this.s=s;
            }
            public void run(){
                    int count=1;
                    String ip=null;
                    try{
                            ip=s.getInetAddress().getHostAddress();
                            System.out.println(ip+"...connected");
                            InputStream in=s.getInputStream();
                            File file=new File(ip+".jpg");    //文件名存为IP地址。
                            //文件存在,则在文件名后面加(1)。
                            while(file.exists())
                                    file=new File(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();
                             new Thread(new PicThread(s)).start();
                     }
                    //ss.close();
             }
     }

2,用户登录的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.8",10008);
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
                //最多就登陆三次,在客户端进行校验。 
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();
System.out.println(ip+"...connected");
try{
                        //登陆三次在服务器端进行限制。 
for(int x=0;x<3;x++){
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
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;
boolean flag=false;
while((line=bufr.readLine())!=null){
if(line.equals(name)){
flag=true;
break;
}
}
                                //设置一个标记判断来向客户端反馈不同的信息。 
if(flag){
System.out.println(name+",已登录");
out.println(name+",欢迎光临");
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();
}
}
}

3, 浏览器服务器。
        自定义一个服务器。
                ServerSocket ss=new ServerSocket(11000);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
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("客户端,你好");
s.close();
ss.close();
控制台得到如下数据:即浏览器向服务器发送的信息,即HTTP消息头。
 
GET / HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave
-flash, application/QVOD, application/QVOD,
Accept-Language: zh-cn     //通过浏览器Internet选项语言设置可以更改。
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Foxy
/1; Shuame)
Accept-Encoding: gzip, deflate
Host: 192.168.1.8:11000
Connection: Keep-Alive     //请求完保持连接,closed请求完自动关闭连接。
利用得到的消息头我们可以模拟一个自定义的浏览器,向tomcat服务器请求数据。
                
Socket s=new Socket("192.168.1.8",8080);
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/demo.html HTTP/1.1");
out.println("*/*");
out.println("Accept-Language: zh-cn");
out.println("Host:192.168.1.8:8080");
out.println("Connection: closed");
以上为 HTTP 请求消息头字段。下面是在控制台打印服务器返回的结果。
out.println();
BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null){
System.out.println(line);
}
s.close();
由打印结果可知,tomcat服务器同样会为自定义浏览器服务,同时会反馈HTTP的响应消息头。
因此我们利用自定义的浏览器就可以随便访问任何网站,百度,新浪等。
当然我们也可以把浏览器做成图形界面,但唯一和缺憾是,无法解析标记语言和脚本语言,这也是浏览器的强大之处。
而在图形化界面中传入地址后,我们需要进行切割来获取对应的信息。 
                ta.setText("");
String url=tf.getText();// http://192.168.1.8:8080/myweb/demo.html
String protocol=url.substring(0,4);
String str1=url.substring(url.indexOf("//")+2);
String str2=str1.substring(0,str1.indexOf("/"));
String[] arr=str2.split(":");
String host=arr[0];
int port=Integer.parseInt(arr[1]);
String path=str1.substring(str1.indexOf("/"));
 
Socket s=new Socket(host,port);
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET "+path+" "+protocol+"/1.1");
out.println("*/*");
out.println("Accept-Language: zh-cn");
out.println("Host:"+str2);
out.println("Connection: closed");
 如此切割非常繁琐,所以API中为我们提供了封装好的类,来进行以上操作,即URL类。 
URL,统一资源定位符 UniformResourceLocator  
URI,通用资源标识符,Uniform Resource Identifier    
URI范围要更大些,包括条形码等。 
URL对象的常用方法:                        
                URL url=new URL("http://192.168.1.9:8080/myweb/demo.html?name=zhangsan&age=33");
System.out.println("getProtocol():"+url.getProtocol());
System.out.println("getHost():"+url.getHost());
System.out.println("getPort():"+url.getPort());
System.out.println("getPath():"+url.getPath());     /myweb/demo.html
System.out.println("getFile():"+url.getFile());        / myweb/demo.html?name=zhangsan&age=33"
System.out.println("getQuery():"+url.getQuery());     name=zhangsan&age=33
                //用?分割,用& 多信息连接,信息都是以键值对存在的。
利用URL类实现浏览器原理。 
 
                                    ta.setText("");
                     URL url=new URL(tf.getText());
                     URLConnection conn=url.openConnection();
                     InputStream in=conn.getInputStream();
 
                    byte[] buf=new byte[1024];
                    int len=in.read(buf);
                    ta.setText(new String(buf,0,len));
         此时控制台输出的结果没有响应头,因为Socket用的TCP协议,工作在传输层,而URL工作在应用层,接收到的数据进行了拆包,所以响应头没有了。

         
注意两个小知识点:
                1,new Socket(),没有指定主机和端口,这是它提供了一个方法connect方法,接收SocketAddress套节字即IP+端口。InetSocketAddress继承SocketAddress抽象类。
                2,new ServerSocket(端口,backlog)。backlog是队列长度,即服务器的最大连接数。  

4,域名解析。
 
C:\WINDOWS\system32\drivers\etc\hosts  用于本地存放ip 地址和域名的对应关系。
 域名访问时先走本地,再
DNS 。输入ip 地址则直接找对应的主机,不走DNS

黑马程序员——17Java网络编程2_第1张图片


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

详情请查看: http://edu.csdn.net/heima  


你可能感兴趣的:(黑马程序员)