黑马程序员_网络编程(2) TCP
2013-03-17 16:25
274 查看
------- android培训、java培训、期待与您交流!
----------
Socket:TCP 传输客户通信端点
ServerSocket:TCP 传输服务端通信端点
因为TCP需要建立连接,所有Socket客户端一建立就要指定服务端的IP和端口。而在服务端建立时,要设置监听的端口。
TCP连接成功后,在客户端和服务端就会产生网络流。
客户端Socket提供对网络流进行读写的输入流和输出流对象。
服务端操作网络流时,先获取客户端Socket对象,然后利用该Socket的字节输入输出流进行读写操作。
客户端与服务端进行多次交互时,注意阻塞式方法对程序的影响。
ServerSocket(int port, int backlog),这个构造函数中backlog用于指定客户端的最大连接数
注意结束标记:可用shutdownOutput() 和 shutdownInput()
eg:
eg:上传图片
TCP端并发访问
客户端并发访问服务器时,把服务端的处理代码封装在Runnable实现子类的run方法中,并把服务器获的的Socket对象传给该实现子类的构造函数。服务端通过while循环启动多个线程,对多个客户端请求进行并发处理。这也是一般服务器的基本原理
eg:
eg:
常用法:
ntgetDefaultPort() :获取与此 URL关联协议的默认端口号。
String getFile() :获取此 URL的文件名。
String getHost() :获取此 URL的主机名(如果适用)。
String getPath() :获取此 URL的路径部分。
int getPort() :获取此 URL的端口号。
String getProtocol():获取此 URL的协议名称。
String getQuery() :获取此 URL的查询部分。
eg:
eg:
------- android培训、java培训、期待与您交流!
----------
----------
一.TCP传输
TCP的两端对应的是客户端和服务端Socket:TCP 传输客户通信端点
ServerSocket:TCP 传输服务端通信端点
因为TCP需要建立连接,所有Socket客户端一建立就要指定服务端的IP和端口。而在服务端建立时,要设置监听的端口。
TCP连接成功后,在客户端和服务端就会产生网络流。
客户端Socket提供对网络流进行读写的输入流和输出流对象。
服务端操作网络流时,先获取客户端Socket对象,然后利用该Socket的字节输入输出流进行读写操作。
客户端与服务端进行多次交互时,注意阻塞式方法对程序的影响。
ServerSocket(int port, int backlog),这个构造函数中backlog用于指定客户端的最大连接数
注意结束标记:可用shutdownOutput() 和 shutdownInput()
eg:
/* 演示TCP传输。 1.tcp分客户端和服务端。 2.客户端对应的对象是Socket。 服务端对应的对象是SeverSocket */ /* 客户端: 通过查阅Socket对象,发现在该对象建立时,就可以连接指定的主机。 因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在, 并连接成功,形成通路后,在该通道进行数据的传输。 需求:给服务段发送一个文本数据。 步骤: 1.创建Socket服务,并指定要连接的主机和端口。 */ import java.io.*; import java.net.*; class TcpClient { public static void main(String[] args) throws Exception { //1.创建客户端的Socket服务,指定目的主机和端口 Socket s = new Socket("192.168.1.13",10003); //2.为了发送数据,应该获取Socket流中的输出流。 OutputStream out =s.getOutputStream(); //3.获取输出流后写入数据。 out.write("Tcp ge men lai le".getBytes()); //socket关闭客户端Socket服务,也就关闭了网络流资源。 s.close(); } } /* 难在服务端上。 需求:定义端点,接受数据,并打印在控制台上。 服务端: 1.建立服务端的Socket服务,通过SeverSocket();并监听一个端口。 2. 获取连接过了的客户端对象。 通过SeverSocket的accept方法。没有就会等,所以这个方法是阻塞式的。 3.客户端如果发过了数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过了的数据。并打印在控制台上。 4.关闭服务。(可选操作,服务端一般是一直开着的)。 */ class TcpServer { public static void main(String[] args) throws Exception { //建立服务端的socket服务,并监听一个端口 ServerSocket ss = new ServerSocket(10003); //通过accept方法获取连接过了的客户端对象,这步很关键。这个方法是阻塞式的 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)); s.close();//关闭客户端 ss.close();//可选操作 } }eg:
/* 需求:建立一个文本转换服务器。 客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端。 而且,客户端可以不断的进行文本转换。当客户端输入over,转换就结束。 分析: 客户端: 既然是操作设备上的数据,那么就可以使用io技术,并按照IO的操作规律来思考。 源:键盘录入 目的:网络设备,也就是网络输出流, 而且操作的是文本数据,可以选择字符流。 步骤: 1,建立服务 2.获取键盘录入 3,将数据发给服务端。 4.获取服务端返回的大写数据。 5.结束,关闭资源。 都是文本数据,可以使用字符流进行操作。同时提高效率,要加入缓冲。 */ import java.io.*; import java.net.*; class TransClient { public static void main(String[] args) throws Exception { Socket s = new Socket("192.168.1.13",10005); //定义读取键盘数据的流对象 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //定义目的,将数据写入socket输出流,发给服务器。 //BufferedWriter bufOut = //new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); PrintWriter out = new PrintWriter(s.getOutputStream(),true); //定义一个socket读取流,读取服务端返回的信息。 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String line = null; while((line=bufr.readLine())!=null)//阻塞位置1,等待键盘录入,没有数据则等待 { if("over".equals(line)) break; //bufOut.write(line); //bufOut.newLine();//没有这一句,则阻塞2的readline不会返回字符, //bufOut.flush();//没有这一句,则数据留在缓冲区中,阻塞2同样阻塞。 out.println(line); String str = bufIn.readLine();//阻塞位置3. System.out.println("server:"+str); } bufr.close(); s.close();//给socket在加入结束标记(-1) } } /* 服务端: 源.socket读取流。 目的:socket输出流 都是文本,装饰 */ class TransServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10005); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+".....connected!"); //读取socket读取流中的数据。 BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); //目的,socket输出流,将大写数据写入到socket输出流,并发送给客户端。 //BufferedWriter bufOut = //new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); PrintWriter out = new PrintWriter(s.getOutputStream(),true); String line = null; while((line=bufIn.readLine())!=null)//阻塞位置2,没有数据+换行符(win中是“\r\n”)则等待,尤其注意换行符 { System.out.println(line); //bufOut.write(line.toUpperCase()); //bufOut.newLine(); //bufOut.flush(); out.println(line.toUpperCase()); } s.close(); ss.close(); } } /* 现象:客户端和服务端都在等待。 为什么呢? 因为客户端和服务端都有阻塞式的方法,这些方法没有读到结束标记,那么就一直等。 而导致两端,都在等待。 */eg:TCP上传文件(IO字节流)
import java.io.*; import java.net.*; class TextClient { public static void main(String[] args) throws Exception { Socket s = new Socket("192.168.1.13",10006); BufferedReader bufr = new BufferedReader(new FileReader("Client.txt")); //在上传文件前,最好先把文件名发给服务端 PrintWriter out =new PrintWriter(s.getOutputStream(),true); String line = null; while((line = bufr.readLine())!=null)// { out.println(line); } //out.println("over"); s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记 -1; BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); String str = bufIn.readLine();//阻塞位置3: System.out.println(str); bufr.close(); s.close(); } } class TextServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10006); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+".......connected!"); BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(new FileWriter("server.txt"),true); String line = null; while((line=bufIn.readLine())!=null)//阻塞位置1: { //if("over".equals(line)) // break; out.println(line); } PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//阻塞位置2: pw.println("上传成功"); out.close(); s.close(); ss.close(); } }
eg:上传图片
/* 需求:上传图片 1. */ /* 客户端: 1.服务端点 2.读取客户端已有的图片数据 3.通过socket的输出流将数据发给服务端。 4.读取服务端反馈信息。 5.关闭。 */ import java.io.*; import java.net.*; class PicClient1 { public static void main(String[] args) throws Exception { Socket s = new Socket("192.168.1.13",10007); FileInputStream fis = new FileInputStream("1.JPG"); 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 inLen = in.read(buf); System.out.println("Server:"+new String(buf,0,inLen)); fis.close(); s.close(); } } /* 服务端: */ class PicServer1 { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10007); Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"......connected!"); InputStream in = s.getInputStream(); FileOutputStream fos = new FileOutputStream("2.JPG"); 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();//服务一次就结束 } }
TCP端并发访问
客户端并发访问服务器时,把服务端的处理代码封装在Runnable实现子类的run方法中,并把服务器获的的Socket对象传给该实现子类的构造函数。服务端通过while循环启动多个线程,对多个客户端请求进行并发处理。这也是一般服务器的基本原理
eg:
import java.io.*; import java.net.*; /* 客户端 */ class PicClient { public static void main(String[] args) throws Exception { //过滤连接 //限定java命令传入的参数只能有1个 if(args.length!=1)// { System.out.println("请选择一个jpg格式的图片"); return; } //判断文件是否是一个存在的文件(不是目录)。 File file = new File(args[0]); if(!(file.exists() && file.isFile())) { System.out.println("该文件有问题,要么不存在,要么不是文件"); return; } //判断这个文件的后缀名是不是.JPG if(!file.getName().endsWith(".JPG")) { System.out.println("图片格式错误,请重新选择"); return; } //限定文件大小在5M以内 if(file.length()>1024*1024*5) { System.out.println("文件过大,没安好心"); return; } Socket s = new Socket("192.168.1.13",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 inLen = in.read(buf); System.out.println("Server:"+new String(buf,0,inLen)); fis.close(); s.close(); } } /* 服务端: 这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程。 这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求。还没有循环回来 执行下次accept方法。所以,暂时获取不到B客户端对象。那么为了可以让多个客户端 同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中去。这 样就可以同时处理多个客户端请求。如何定义线程?只要明确了每一个客户端要在服务端 执行的代码即可。将该代码存入run方法中。 */ 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(); } } } class PicThread implements Runnable { private Socket s; PicThread(Socket s) { this.s = s; } public void run() { String ip = s.getInetAddress().getHostAddress(); int count = 0; try { System.out.println(ip+"......connected!"); InputStream in = s.getInputStream(); File file = new File(ip+"("+(count)+")"+".JPG"); while(file.exists()) file = new File(ip+"("+(count++)+")"+".JPG");//注意new File并不在磁盘上创建文件。 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+"上传失败"); } } }客户端并发登陆:
/* 客户端通过键盘录入用户名: 服务端对这个用户名进行校验。 如果该用户存在,在服务器端显示***,已登录。 并在客户端显示:***,欢迎光临。 如果该用户不存在,在服务器端显示 ***,尝试登陆 并在客户端显示 ***,该用户不存在。 最多就登陆三次。 */ import java.io.*; import java.net.*; /* 客户端: */ class LoginClient { public static void main(String[] args) throws Exception { Socket s = new Socket("192.168.1.13",10008); BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(s.getOutputStream(),true); BufferedReader in = 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 = in.readLine(); System.out.println("info:"+info); if(info.contains("欢迎")) break; } bufr.close(); s.close(); } } /* 服务端: */ class LoginServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(10008); while(true) { Socket s = ss.accept(); new Thread(new LoginThread(s)).start(); } } } class LoginThread implements Runnable { private Socket s; LoginThread(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 in = new BufferedReader(new InputStreamReader(s.getInputStream())); String name = in.readLine(); if(name==null) break; BufferedReader bufr = new BufferedReader(new FileReader("user.txt")); PrintWriter out = new PrintWriter(s.getOutputStream(),true); boolean flag = false; String line =null; 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+":校验失败"); } } }自定义游览器与服务器
eg:
/* 演示客户端和服务端。 1.客户端:浏览器。 服务端:自定义 2. 客户端是浏览器 服务端:TomCat服务器。 3. 客户端:自定义 服务器: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(); 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("<font color ='red' size = '10'>客户端你好"); s.close(); ss.close(); } }eg:
import java.io.*; import java.net.*; class MyIE { public static void main(String[] args) throws Exception { //浏览器内部建立Socket客户端 Socket s = new Socket("192.168.1.13",8080); //想服务器发送请求消息头 PrintWriter out = new PrintWriter(s.getOutputStream(),true);//别忘了加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.13:11000"); out.println("Connection: Keep-Closed"); out.println(); out.println();//请求消息头末尾一定要有一行空行。 System.out.println("over1"); //读取服务器发送过来的响应消息头和数据体。 BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream())); String line = null; while((line=bufr.readLine())!=null) { System.out.println(line); } s.close(); } } /* http://192.168.1.13:11000/myweb/demo.html 客户端http请求消息头, GET /myweb/demo.html HTTP/1.1 Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gi f, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd .ms-powerpoint, application/msword, application/x-shockwave-flash, application/Q VOD, application/QVOD, Accept-Language: zh-CN User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5. 0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Cent er PC 6.0; .NET4.0C; BOIE9;ZHCN) Accept-Encoding: gzip, deflate Host: 192.168.1.13:11000 Connection: Keep-Alive */ /* 服务器:HTTP响应消息头 HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Accept-Ranges: bytes ETag: W/"315-1358328614234" Last-Modified: Wed, 16 Jan 2013 09:30:14 GMT Content-Type: text/html Content-Length: 315 Date: Wed, 16 Jan 2013 10:03:30 GMT <html> <body> <h1>这是我的主页</h1> <font size = 5 color = red >欢迎光临 </font> <div> 放大放大是否</br> 顶顶顶顶</br> 发的说法</br> </div> </body> </html> */
二.URL
统一资源标识符,而 URL是统一资源定位符常用法:
ntgetDefaultPort() :获取与此 URL关联协议的默认端口号。
String getFile() :获取此 URL的文件名。
String getHost() :获取此 URL的主机名(如果适用)。
String getPath() :获取此 URL的路径部分。
int getPort() :获取此 URL的端口号。
String getProtocol():获取此 URL的协议名称。
String getQuery() :获取此 URL的查询部分。
eg:
import java.net.*; class URLDemo { public static void main(String[] args) throws Exception { //URL url=new URL("http://192.168.1.13:11000/myweb/demo.html"); URL url=new URL("http://192.168.1.13:11000/myweb/demo.html?name=haha&age=30"); System.out.println("getProtocol():"+url.getProtocol()); //http System.out.println("getHost():"+url.getHost());//192.168.1.13 System.out.println("getDefaultPort():"+url.getDefaultPort());//80,如果关联的协议没有默认的端口,则值为-1; System.out.println("getPort():"+url.getPort()); // 11000,如果没有设置则为-1; System.out.println("getPath():"+url.getPath());// /myweb/demo.html System.out.println("getFile():"+url.getFile());///myweb/demo.html?name=haha&age=30 System.out.println("getQuery():"+url.getQuery());//name=haha&age=30 /* int port = url.getPort(); if(port==-1) port =80; getPort() = -1 */ } }URLConnection:内部封装了Socket,所以可以获取网络输入输出流
eg:
import java.net.*; import java.io.*; class URLConnectionDemo { public static void main(String[] args) throws Exception { URL url=new URL("http://192.168.1.13:8080/myweb/demo.html"); URLConnection conn = url.openConnection(); System.out.println(conn); InputStream in = conn.getInputStream(); byte [] buf =new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); } }
------- android培训、java培训、期待与您交流!
----------
相关文章推荐
- 黑马程序员------网络编程(No.2)(TCP)
- 黑马程序员---网络编程(UDP、TCP)
- 【黑马程序员】黑马入学准备篇:网络编程之 TCP、UDP和Socket综合实例
- 黑马程序员_java高级篇网络编程TCP实战Day8(上)
- 黑马程序员——Java网络编程(TCP和UDP)
- 黑马程序员-网络编程TCP练习(客户端)
- 黑马程序员_网络编程二(Tcp练习,URL-URLConnection,网络知识,域名解析)
- java 网络编程 tcp黑马程序员学习笔记(4)
- 黑马程序员_网络编程TCP之学习笔记
- 黑马程序员_网络编程之TCP和UDP
- 黑马程序员--图形界面中的鼠标,键盘两个事件,做一个磁盘的文件列表,菜单,子菜单,模拟记事本。网络编程,TCP的通信协议的特点
- 黑马程序员-----网络编程中Tcp练习
- 黑马程序员-网络编程之TCP传输小总结
- 黑马程序员--10.网络编程--08.【C_S常见的“双卡”现象和解决--TCP复制文本文件示例II】【阻塞式循环的分析过程 ---总结】
- 黑马程序员——java网络编程中的传输协议:UDP和TCP
- 黑马程序员--java基础--网络编程(UDP和TCP)
- 黑马程序员_Java网络编程之TCP应用
- 黑马程序员-网络编程之TCP传输小总结
- 黑马程序员 ---网络编程 TCP
- 黑马程序员--10.网络编程--02.【网络传输三要素在Java中的体现】【TCP和UDP概念】【Socket基本概念】