通过练习掌握TCP在进行传输过程中的问题



练习1:创建一个英文大写转换server

client输入字母数据,发送给服务端,服务端收到后显示到控制台,并将该数据转成大写返回client,知道client输入over,转换结束

public class Main {

	public static void main(String[] args) throws IOException{
Text_Transform_Client();
Text_Transform_Server();
} public static void Text_Transform_Server() throws IOException {
//文本转服务端 /* 转换服务端
* 1.创建ServerSocket服务端对象
* 2.获取Socket对象
* 3.源:Socket,读取client发过来须要转换的数据
* 4.汇:显示在控制台
* 5.将数据转成大写返回client
*/
//创建服务端对象
ServerSocket ss = new ServerSocket(6534); //获取socket对象
Socket socket = ss.accept(); //获取ip,明白是谁连进来的
String ip = socket.getInetAddress().getHostAddress();
System.out.println("ip : "+ip); //获取socket读取流,并装饰
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//获取socket输出流,并装饰
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
//new PrintWriter(socket.Outputtream())
String line = null;
while((line = br.readLine())!=null){
System.out.println(line);
pw.println(line.toUpperCase());//pw.print(line.tpUpperCase+"\r\n");
} //pw.flush();
socket.close();
ss.close();
} public static void Text_Transform_Client() throws IOException{
//文本转换client
/*
* 转换client:
* 1.创建Socketclient对象
* 2.获取键盘录入
* 3.将录入的信息,发送给Socket输出流
*/
Socket socket = new Socket("127.0.0.1",6534);
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in)); //源是:键盘,汇:Socket输出流
//new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
//new PrintWriter(socket.getOutstream());
//Socket输入流,读取服务端返回的大写数据
BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = null;
while((line = br.readLine())!=null){
if("over".equals(line))break; pw.println(line);//pw.print(line+"\r\n")
//pw.flush();
//读取服务端返回的大写信息
String str = br2.readLine();
System.out.println("up : "+str);
}
socket.close();
}
}

常见问题:

一、上述代码有一个问题,就是client输入over后client结束,服务端有没有结束?

    结束,readline()方法是堵塞式方法,可是在client输入over后,client的socket关闭返回一个-1,服务端的readline()方法中的read方法读取-1,所以readline()方法就读取到null,所以会结束。



二、假设在client和服务端的PrintWriter pw = new PrintWriter(socket.getOutputStream())的自己主动刷新去掉,pw.print()的自己主动换行去掉,会发生什么?

   client没有收到转换后的数据,服务端没有显示数据

由于在client,pw.print()写入的数据,都写到了PrintWriter中,并没有刷新到socket输入流中

PS:这就是TCP在传输过程中出现两端都在等待的情况,非常可能是数据没有发出去,最大的可能就是有堵塞式方法。

当然,能够在pw.print();下加pw.flush(),可是问题依然,由于readline读取结束的标记是换行,所以在client的pw.print(+"\r\n"),所以要想 解决这个问题,就要在client和服务端都加上刷新动作,和换行符。

一旦遇到上述问题,一般都是由于堵塞式方法造成的服务端、client都在等待的情况,所以依照上述代码演示样例所写,比較好



练习2:上传文本文件

public class Main {

	public static void main(String[] args)throws IOException{
UpText_Client();
UpText_Server();
} public static void UpText_Server() throws IOException { ServerSocket ss = new ServerSocket(6534);
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bw = new BufferedWriter(new FileWriter("c:\\server.txt")); String line = null;
while((line = br.readLine())!=null){
//if("over".equals(line))break;//*
bw.write(line);
bw.newLine();//*
bw.flush();//*
} PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
pw.println("上传成功"); br.close();
bw.close();
socket.close();
ss.close();
} public static void UpText_Client() throws IOException { Socket socket = new Socket("127.0.0.1",6534);
BufferedReader br = new BufferedReader(new FileReader("c:\\data.txt"));
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
String line = null;
while((line = br.readLine())!=null){
out.println(line);
}
//out.println("over");//*,开发的时候一般都是应用时间戳,做结束标记,先发给服务器一下时间戳,输入结束后,再发一次
//socket里有方法
socket.shutdownOutput();//告诉服务端数据写完了 //读取socket流
BufferedReader brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String string = brin.readLine();
System.out.println(string);
br.close();
socket.close();
}
}

*号处要注意,漏写easy造成,等待清理,client输入完成后,服务端还在等待,不知道client已经输入完成,堵塞,等待

演示的时候,分为两个主函数演示

练习3:上传图片

上传图片到client

public static void main(String[] args)throws IOException{
UpText_Client();
}
public static void UpText_Client() throws IOException { //创建client
Socket socket = new Socket("127.0.0.1",6534); //读取client要上传的图片文件
FileInputStream fis = new FileInputStream("c:\\1.jpg"); //获取socket输出流,将得到的图片数据发给服务端
OutputStream out = socket.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!=-1){
out.write(buf, 0, len);
} //告诉服务端,client数据发送完成,使其读取结束
socket.shutdownOutput(); InputStream in = socket.getInputStream();
byte[] buf2 = new byte[1024];
int len2 = in.read(buf2);
String result = new String(buf2,0,len2);
System.out.println(result);
socket.close();
fis.close(); }

上传图片到服务端

public static void main(String[] args)throws IOException {
UpText_Server();
}
public static void UpText_Server() throws IOException {
//创建服务端
ServerSocket ss = new ServerSocket(6534); //获取client
Socket socket = ss.accept();
//读取client发来的数据
InputStream in = socket.getInputStream(); String ip = socket.getInetAddress().getHostAddress();
System.out.println("IP : "+ip+"....connect");
//将读取的数据存储到文件里
File dir = new File("c:\\CopyPic111111111");
if (!(dir.exists())) {
dir.mkdirs();
}
File file = new File(dir,ip+".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);
}
//获取socket输出流,显示上传结果
OutputStream out = socket.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
socket.close();
ss.close();
}

上述代码的服务端仅仅能获取一个client上传,多个则不行。

服务端获取了1号client正在处理1号client,那么2号client就必需要等待,等待时间过长,就会连接超时,所以服务端结合线程,获取client对象为一个线程,处理client信息为一个线程,不停的切换,就能够实现多个client上传图片到服务端



服务端结合线程,改进

client部分不变

服务端

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Up { private static ServerSocket ss;
public static void main(String[] args)throws IOException {
UpText_Server();
}
public static void UpText_Server() throws IOException { ss = new ServerSocket(6534); while(true){
Socket socket = ss.accept();//不停的接收client对象
new Thread(new UPtask(socket)).start();//创建多个线程运行不同client的信息
}
}
}

服务端线程

public class UPtask implements Runnable {
private Socket socket;
public UPtask(Socket socket){
this.socket = socket;
}
public void run() {
int count = 1;
try {
String ip = socket.getInetAddress().getHostAddress();
System.out.println("IP : "+ip+"....connect");
InputStream in = socket.getInputStream(); File dir = new File("c:\\CopyPic111111111");
if (!(dir.exists())) {
dir.mkdirs();
}
File file = new File(dir,ip+".jpg");
//假设已经存在
while(file.exists()) {
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);
}
//获取socket输出流,显示上传结果
OutputStream out = socket.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
socket.close();
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException("server异常,请稍等");
}
}
}

UDP和TCP的差别:

UDP:将数据打包,有限制,不连接,效率高,不安全,easy丢包

TCP:建立数据通道,无限制,效率低,安全





JAVA学习第六十二课 — TCP协议练习的更多相关文章

  1. JAVA学习第五十二课 — IO流(六)File对象

    File类 用来给文件或者目录封装成对象 方便对文件与目录的属性信息进行操作 File对象能够作为參数传递给流的构造函数 一.构造函数和分隔符 public static void FileDemo( ...

  2. JAVA学习第六十四课 — 反射机制

       Java反射机制是在执行状态中,对于随意一个类,都可以知道这个类的全部属性和方法,对于随意一个对象,都可以调用它的随意一个方法和属性,这样的动态获取的信息以及动态调用对象的方法的功能称为java ...

  3. JAVA学习第三十二课(经常使用对象API)- 基本数据类型对象包装类

    将基本数据类型(8种:int..)封装成对象的优点就是能够在对象中封装很多其它的功能和方法来操控该数据 常见的操作就是:用于基本数据类型与字符串之间的转换 基本数据类型对象包装类一般用于基本类型和字符 ...

  4. JAVA学习第六十五课 — 正則表達式

    正則表達式:主要应用于操作字符串.通过一些特定的符号来体现 举例: QQ号的校验 6~9位.0不得开头.必须是数字 String类中有matches方法 matches(String regex) 告 ...

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. JAVA学习第五十九课 — 网络编程概述

    网络模型 OSI(Open System Interconnection)开放系统互连:參考模型 TCP/IP 网络通讯要素 IP地址 port号 传输协议 网络參考模型 七层OSI模型的基本概念要了 ...

  7. JAVA学习第四十八课 — IO流(二):文件的复制 & 缓冲区1

    一.复制文本文件 将G盘的文本文件拷贝到D盘上 也就是 读取G盘中文本文件的数据.写入D盘中->连读带写 而剪切呢.就是连读带写后,删除原盘的文件 <span style="fo ...

  8. Java学习笔记【十二、网络编程】

    原计划的学习结束时间是3月4日,目前看来已经延迟了,距离低标还差一些,多方面原因,也不找借口,利用周末赶赶进度,争取本周末把低标完成吧! 参考: http://www.runoob.com/java/ ...

  9. JAVA学习第三十四课 (经常使用对象API)—List集合及其子类特点

    整个集合框架中最经常使用的就是List(列表)和Set(集) 一.List集合 && Set的特点 Collection的子接口: 1.List:有序(存入和取出的顺序一致),元素都有 ...

随机推荐

  1. Docker创建支持ssh服务的容器和镜像

    原文链接:Docker创建支持ssh服务的容器和镜像 1. 这里使用的centos作为容器,所以首先下载centos的images # sudo docker pull centos 2. 下载后执行 ...

  2. php文件操作基本使用方法

    <?php /* $fp=fopen("tmp.html","r"); $str=fread($fp,filesize("tmp.html&qu ...

  3. Git代理服务器设置和访问Github

    因为现在工作的网络环境有着非常严格的限制,.可以说,在最近的访问通过代理Github它采取了一些曲折的.也积累了一些相关经验.我们认为有必要注意什么. 符合"不要再发明轮子"宗旨, ...

  4. 重新想象 Windows 8 Store Apps (7) - 控件之布局控件: Canvas, Grid, StackPanel, VirtualizingStackPanel, WrapGrid, VariableSizedWrapGrid

    原文:重新想象 Windows 8 Store Apps (7) - 控件之布局控件: Canvas, Grid, StackPanel, VirtualizingStackPanel, WrapGr ...

  5. OpenVPN-ng,为移动续航的应用层隧道

    VPN,让人觉得它总是做好事的,是逃离监管的途径,其实VPN已经成了逃离监管的唯一代名词.你看,无论是什么技术,IPSec也好,WEB代理也罢,仅仅要是加密了原始信息的技术,都能够叫做VPN,于是乎就 ...

  6. 什么是“Bash”破绽?

    摘要:近来的linux系统出现"Bash"漏洞可以被认为是第一个互联网造成安全讨论和思考.错的资料. 什么是"Bash"漏洞?它是怎样工作的?它是否可以成为新的 ...

  7. AndroidService 深度分析(2)

    AndroidService 深度分析(2) 上一篇文章我们Service的生命周期进行了測试及总结. 这篇文章我们介绍下绑定执行的Service的实现. 绑定执行的Service可能是仅为本应用提供 ...

  8. 3g自己主动更新网卡驱动web完架构文档

    几年前写. 看它是否是用得上 1  简单介绍 本文档具体描写叙述了基于ASP.NET平台和IIS服务的T-Mobile自己主动更新系统的实现框架. 本文档主要从技术架构和业务架构两个方面来着手来描写叙 ...

  9. 北邮iptv用WindowsMediaplayer打不开的解决的方法

    前言:之前我的iptv能够用,可是有次我安装了realplayer,它就偷偷把iptv文件的默认打开方式给篡改了,卸载了                  realplayer之后,iptv不能直接用 ...

  10. php xss过滤

    XSS已知CSS (Cross Site Script) ,跨站点脚本攻击.它指的是恶意攻击者Web插入恶意网页html代码,当用户浏览网页.其中嵌入Web里面html代码运行,从而实现了一些人的攻击 ...