文章目录
- TCP协议
- TCP协议编程服务器获取到数据给一个反馈
- TCP协议编程客户端键盘录入,服务器输出到控制台。
- TCP协议编程客户端键盘录入,服务器输出文本文件。
- TCP协议编程客客户端文本文件,服务器输出到控制台
- TCP协议编程上传文件,并给出反馈。
- TCP协议编程上传图片,并给出反馈。
- TCP协议编程多线程上传图片,并给出反馈。
TCP协议
java.net.Socket:此类实现客户端套接字(也可以就叫“套接字”)。
java.net.ServerSocket:此类实现服务器套接字。
TCP:
建立连接通道
数据无限制
速度慢
可靠
连接被拒绝。TCP协议一定要先看服务器。
java.net.ConnectException: Connection refused: connect
TCP协议发送和接收数据图解
TCP协议编程演示
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端对象
//Socket(InetAddress address, int port):使用InetAddress指定ip和指定端口。
//Socket(String host, int port):指定ip和端口
//Socket s = new Socket(InetAddress.getByName("192.168.150.1"),10003);
Socket s= new Socket("192.168.150.1",10003);
//2.获取输出流,写数据。
OutputStream os = s.getOutputStream();//阻塞式方法,有数据才写。
byte[] bytes = "天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然也!".getBytes();
os.write(bytes);
//3.释放资源
s.close();
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP服务器端Socket对象
ServerSocket ss = new ServerSocket(10003);
//2.Socket accept():监听客户端连接,返回一个Socket对象
Socket s = ss.accept();//听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
//3.获取输入流,并打印到控制台
InputStream is = s.getInputStream();//阻塞式方法,有数据才读。
byte[] bytes = new byte[1024];
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
//关闭资源
//ss.close(); 这个不应该关闭。
s.close();
}
}
结果:
天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然也!
TCP协议编程服务器获取到数据给一个反馈
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端Socket
Socket s = new Socket("192.168.150.1", 10004);
//2.使用Socket对象获取输入流对象
//写数据
OutputStream os = s.getOutputStream();
byte[] bytes = "天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然也!".getBytes();
os.write(bytes);
//B解决方案
// s.shutdownOutput();
//读数据(服务端读取反馈)
InputStream is = s.getInputStream();
byte[] bytes2 = new byte[1024];
int len = is.read(bytes2);//阻塞式方法,有数据才读。
String str = new String(bytes2, 0, len);
System.out.println(str);
//3.释放资源
s.close();
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP服务端对象
ServerSocket ss = new ServerSocket(10004);
//2.监听客户端连接
Socket s = ss.accept();//阻塞式方法
//3.根据Soket对象,获取输入流对象
//读数据
InputStream is = s.getInputStream();
byte[] bytes = new byte[1024];
//这里段代码有问题?
//最主要是出现在了while循环的判断上,第一次判断是有数据的,1024个字节完全可以全部接收,数据已经读完了。
//但是还要判断一下,这时候已经没有数据可以读了,因为is.read(bytes)是一个阻塞式方法根本读不到-1,所以就在这里一直等。
//数据过来。服务端就不能执行向客户端写数据的代码。所以客户端就看不到“数据收到了字样”
//解决:
//A:去掉这里的while循环
//B:客户端写入数据后,给一个反馈我没有数据了,让服务端不要在等了。
/* while ((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}*/
//A解决方案
int len = is.read(bytes);//阻塞式方法
System.out.println(new String(bytes, 0, len));
//4.服务端已经读取到了数据,给一个反馈。
OutputStream os = s.getOutputStream();
os.write("数据收到了".getBytes());
//关闭资源
//ss.close();//这个不应该关闭的
s.close();
}
}
结果:
客户端
数据收到了
服务端
天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然也!
TCP协议编程客户端键盘录入,服务器输出到控制台。
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端Socket对象
Socket s = new Socket("192.168.1.134",10011);
//创建字符输入流对象(模拟键盘录入)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//2.通过Socket对象获取输入流对象
//将输入流包装一下
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
if("886".equals(line)){
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
//3.释放资源
s.close();
bw.close();
br.close();
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP服务端的Socket对象
ServerSocket ss = new ServerSocket(10011);
//2.监听客户端
Socket s = ss.accept();//阻塞式方法
//3.读取数据
//包装成字符输入流
//注意:客户端我使用的是字符高效流服务端使用的死字节流
InputStream is = s.getInputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {//阻塞式方法
System.out.print(new String(bytes, 0, len));
}
//释放资源
s.close();
//ss.close(); 服务器不能停止
}
}
结果:
客户端
千锤万找出深山,烈火焚烧若等闲。
粉身碎骨全不怕,要留清白在人间。
886
服务端
千锤万找出深山,烈火焚烧若等闲。
粉身碎骨全不怕,要留清白在人间。
TCP协议编程客户端键盘录入,服务器输出文本文件。
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端Socket对象
Socket s = new Socket("192.168.1.134", 11111);
//获取输入流对象(模拟键盘录入)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//2.包装Socket输出流对象
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//读取数据
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
//3.释放资源
s.close();
br.close();
// bw.close();s关闭了,相当于bw关掉了。
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP服务端Socket对象
ServerSocket ss = new ServerSocket(11111);
//2.监听客户端
Socket s = ss.accept();
//创建字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
//3.包装Socket输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//4.关闭资源
bw.close();
s.close();
//br.close();s关闭了,这个就也关闭了
//ss.close();//服务器不能关闭
}
}
结果:a.txt文件结果
天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然而。
且随疾风前行身后亦需留心。
如遇赴死易如反掌。
TCP协议编程客客户端文本文件,服务器输出到控制台
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端Socket对象
Socket s = new Socket("192.168.1.134", 11111);
//创建字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//2.封装Socket获取输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//读取数据
String line =null;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//3.关闭资源
s.close();
bw.close();//s已经关闭了,这里就不需要了。
br.close();
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建TCP服务端Socket对象
ServerSocket ss =new ServerSocket(11111);
//2.监听客户端
Socket s = ss.accept();
//3.通过Socket对象获取输入流
//注意:客户端使用的字符流,服务端使用字节流
InputStream is = s.getInputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len=is.read(bytes))!=-1){
System.out.print(new String(bytes,0,len));
}
//4.关闭资源
//ss.close();
s.close();
}
}
结果:
天降大任于斯人也,比先苦其心志,劳其筋骨,饿其体肤,揉食指然而。
且随疾风前行身后亦需留心。
如遇赴死易如反掌。
TCP协议编程上传文件,并给出反馈。
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
出现客户端反馈信息接收不到:
按照正常的思路加入反馈信息,结果却没反应。为什么呢?
读取文本文件是可以以null作为结束信息的,但是呢,通道内是不能这样结束信息的。
所以,服务器根本就不知道你结束了。而你还想服务器给你反馈。所以,就相互等待了。
如何解决呢?
A:在多写一条数据,告诉服务器,读取到这条数据说明我就结束,你也结束吧。
这样做可以解决问题,但是不好。(如果文件中刚好有这个标记,那就后面的内容读取不到)
B:Socket对象提供了一种解决方案
public void shutdownOutput()
public class UploadClient {
public static void main(String[] args) throws IOException {
//1.创建TCP客户Socket对象
Socket s =new Socket("192.168.1.134",11112);
//创建字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("zuowen.txt"));
//2.包装Socket对象
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//读数据
String line = null;
while((line=br.readLine())!=null){//阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//写一个标记
//bw.write("over"); 这个其实不好,如果文件中的内容有over就会出现,后面的内容读取不到。
//客户端写完数据后,通知服务端不要再等了,我已经没有数据了
s.shutdownOutput();
//接收返回反馈信息
//因为卡在服务端读数据那块,这里也一直在等数据。
InputStream is = s.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);//阻塞
System.out.println(new String(bytes,0,len));
//3.关闭资源
s.close();
br.close();
//bw.close();s关闭了这个就关闭了
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class UploadServer {
public static void main(String[] args) throws IOException {
//1.创建TCPSocket对象
ServerSocket ss = new ServerSocket(11112);
//2.监听客户端
Socket s = ss.accept();//阻塞
//创建字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));
//3.封装Socket对象获取的输入流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//读取数据
//客户端读取不了反馈信息。
//问题是出现br.readLine()方法上,因为是一个阻塞式方法在流通道内读取不到null,所以就一直在这里
//等客户端的数据。
String line = null;
while ((line= br.readLine())!=null){//阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//读取完数据后,给一个反馈信息。
OutputStream os = s.getOutputStream();
os.write("文件已上传".getBytes());
//4.关闭资源
//ss.close(); 服务端不关闭
s.close();
bw.close();
//br.close();s关闭了,这里就不需要关闭了。
}
}
结果:
Copy文件中的内容
相去万千里,各在天一涯。以前,距离是故园东望路漫漫,
双袖龙钟泪不干的无奈;是羌笛何须怨杨柳,春风不度玉门关的自嘲;
亦是守着窗儿,独自怎生得黑的横亘生死......但在现代科技的飞速发展下,
现在,无论是在东北半球,还是在西南半球,一个skype,一次face...
客户端控制台的内容
文件已上传
TCP协议编程上传图片,并给出反馈。
这里有二个问题就是字节流复制图片,应该也要加上刷新缓冲区不然会出现图片复制不完全:
问题一:
问题二:
通过while循环可以改进一个服务器接收多个客户端。
但是这个是有问题的。
如果是这种情况,假设我还有张三,李四,王五这三个人分别执行客户端
王五网速很快,但是要等张三和李四执行完。(其实就是因为单线程)
张三:好好学习.avi(100M) 256k
李四:天天向上.mp3(3M) 1M
王五:ILoveJava.txt(1k) 100M
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class UploadClient {
public static void main(String[] args) throws IOException {
//1.创建TCP客户端Soket对象
Socket s = new Socket("192.168.1.134", 11112);
//创建字节输入流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("歼20战斗机.jpg"));
//封装Socket对象输出流对象
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
//写数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes)) != -1) {//阻塞
bos.write( bytes,0,len);
//防止图片写不全
bos.flush();
}
//通知服务端我已经没数据,不要等待了
s.shutdownOutput();
//接收服务端返回数据
InputStream is = s.getInputStream();
byte[] bytes2 = new byte[1024];
int len1 = is.read(bytes2);//阻塞
System.out.println(new String(bytes2,0,len1));
//关闭资源
s.close();
bis.close();
//bos.close();s已经关闭,不需要在关闭了。
//is.close();s已经关闭,不需要在关闭了。
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class UploadServer {
public static void main(String[] args) throws IOException {
//1.创建TCP服务端Socket对象
ServerSocket ss = new ServerSocket(11112);
//2.监听客户端
Socket s = ss.accept();//阻塞
//创建字节输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mn.jpg"));
//封装Socket对象获取的输出流
BufferedInputStream bis =new BufferedInputStream(s.getInputStream());
//读数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len=bis.read(bytes))!=-1){//阻塞
bos.write(bytes,0,len);
//防止图片写不全
bos.flush();
}
//读取完数据给一个反馈
OutputStream os = s.getOutputStream();
os.write("图片上传完成".getBytes());//阻塞
//3.关闭资源
//ss.close(); 服务端不能关闭
bos.close();
s.close();
//bis.close();s已经关闭了,不需要关闭了
//os.close();s已经关闭了,不需要关闭了
}
}
结果:
mn.jpg
客户端控制台
图片上传完成
TCP协议编程多线程上传图片,并给出反馈。
启动多个线程复制图片
多线程测试
public class ThreadDemo {
public static void main(String[] args) {
//创建线程对象
UploadClient uc = new UploadClient();
UploadServer us = new UploadServer();
//启动线程;
uc.start();
us.start();
}
}
TCP协议发送数据:
A:创建发送端的Socket对象
这一步如果成功,就说明连接已经建立成功了。
B:获取输出流,写数据
C:释放资源
public class UploadClient extends Thread {
@Override
public void run() {
try {
//1.创建TCP客户端Soket对象
Socket s = new Socket("192.168.1.134", 11112);
//创建字节输入流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("歼20战斗机.jpg"));
//封装Socket对象输出流对象
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
//写数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes)) != -1) {
bos.write( bytes,0,len);
//防止图片写不全
bos.flush();
}
//通知服务端我已经没数据,不要等待了
s.shutdownOutput();
//接收服务端返回数据
InputStream is = s.getInputStream();
byte[] bytes2 = new byte[1024];
int len1 = is.read(bytes2);
System.out.println(new String(bytes2,0,len1));
//关闭资源
s.close();
bis.close();
//bos.close();s已经关闭,不需要在关闭了。
//is.close();s已经关闭,不需要在关闭了。
}catch (IOException e){
e.printStackTrace();
}
}
}
TCP协议接收数据:
A:创建接收端的Socket对象
B:监听客户端连接。返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台
D:释放资源
public class UploadServer extends Thread {
@Override
public void run() {
try{
//1.创建TCP服务端Socket对象
ServerSocket ss = new ServerSocket(11112);
//2.监听客户端
Socket s = ss.accept();
//避免文件名字重复
String fileName = System.currentTimeMillis()+new Random().nextInt(9999)+".jpg";
//创建字节输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));
//封装Socket对象获取的输出流
BufferedInputStream bis =new BufferedInputStream(s.getInputStream());
//读数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
//防止图片写不全
bos.flush();
}
//读取完数据给一个反馈
OutputStream os = s.getOutputStream();
os.write("图片上传完成".getBytes());
//3.关闭资源
//ss.close(); 服务端不能关闭
bos.close();
s.close();
//bis.close();s已经关闭了,不需要关闭了
//os.close();s已经关闭了,不需要关闭了
}catch (IOException e){
e.printStackTrace();
}
}
}
结果:
客户端控制台
图片上传完成