Day23-3
1 TCP编程
- TCP编程步骤
客户端:
1、创建Socket对象,建立和服务端的连接
2、获取网络输出流
3、通过I\O的操作来发送数据
4、关闭资源
服务端:
1、创建ServerSocket对象,开启服务器,监听指定端口
2、调用accept方法,接收客户端发来的请求,返回一个Socket对象
3、获取服务端的网络输入流
4、通过I\O的操作来读取数据
5、关闭资源 - 客户端建立连接方式:
Socket(InetAddress ip, int port)
:建立一个通信点,专门用于和ip主机的port程序进行通信。
getOutputStream()
:获取客户端的输出流对象,用于写出信息
注意:
当对象创建之后并启动成功,表示已经和服务端建立连接,否则建立连接失败 - 服务端建立连接方式:
ServerSocket(int port)
:创建一个服务端端口对象,用于连接客户端
accept()
:获取一个和客户端交互的Socket对象
getInputStream()
:获取输入流,用于接收客户端发来的数据
1.1 客户端代码
package tcp.demo1;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws IOException {
//1、创建一个通信点,要和服务端进行连接
Socket sk = new Socket(InetAddress.getByName("192.168.38.226"),10010);
//2、要获取一个网络流,用来发送信息
OutputStream os = sk.getOutputStream();
//3、使用流中的发送功能
String str = "你好";
os.write(str.getBytes());
//4、关闭即可
sk.close();
}
}
1.2 服务端
package tcp.demo1;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//1、需要先建立一个和客户端进行连接的端口
ServerSocket ssk = new ServerSocket(10010);
//2、获取一个用来接收客户端信息的端口
Socket sk = ssk.accept();
//3、获取一个输入流,读取信息
InputStream is = sk.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println(new String(bs,0,len));
//4、关闭通信点
ssk.close();
}
}
2 案例1
需求:
(1)客户端使用键盘录入直接发送一个字符串
(2)服务端使用高效流读取字符串
2.1 客户端代码
package tcp.demo2;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
//创建一个客户端的通信点
Scanner sc = new Scanner(System.in);
Socket sk = new Socket(InetAddress.getByName("192.168.38.226"),10010);
//获取一个输出流
OutputStream os = sk.getOutputStream();
//将字节流包装为以字符流:
OutputStreamWriter osw = new OutputStreamWriter(os);
//再将字符流包装为以高效字符流:
BufferedWriter bw = new BufferedWriter(osw);
//直接传输一个字符串:
while(true){
System.out.println("请录入您要发出的请求:");
String str = sc.nextLine();
if(str.equals("end")){
break;
}
bw.write(str);
bw.newLine();
bw.flush();
}
//关闭通信点
sk.close();
}
}
2.2 服务端代码
package tcp.demo2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//创建一个用来连接的通信点
ServerSocket ssk = new ServerSocket(10010);
//获取一个通信点用来读取数据
Socket sk = ssk.accept();
//获取一个输入流
InputStream is = sk.getInputStream();
//将字节输入流,包装为一个字符流
InputStreamReader isr = new InputStreamReader(is);
//再将该字符流,包装为一个高效字符流
BufferedReader br = new BufferedReader(isr);
String str;
while((str = br.readLine()) != null){
System.out.println("接收到的数据为:" + str);
}
ssk.close();
}
}
3 案例2
需求:
(1)服务端接收到客户端发来的请求后,给客户端反馈信息
(2)客户端接收反馈信息
3.1 客户端
package tcp.demo2;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
//创建一个客户端的通信点
Scanner sc = new Scanner(System.in);
Socket sk = new Socket(InetAddress.getByName("192.168.38.226"),10010);
//获取一个输出流
OutputStream os = sk.getOutputStream();
//将字节流包装为以字符流:
OutputStreamWriter osw = new OutputStreamWriter(os);
//再将字符流包装为以高效字符流:
BufferedWriter bw = new BufferedWriter(osw);
//直接传输一个字符串:
while(true){
System.out.println("请录入您要发出的请求:");
String str = sc.nextLine();
if(str.equals("end")){
break;
}
bw.write(str);
bw.newLine();
bw.flush();
//接收服务端的反馈信息:
InputStream is = sk.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println(new String(bs,0,len));
}
//关闭通信点
sk.close();
}
}
3.2 服务端
package tcp.demo2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//创建一个用来连接的通信点
ServerSocket ssk = new ServerSocket(10010);
//获取一个通信点用来读取数据
Socket sk = ssk.accept();
//获取一个输入流
InputStream is = sk.getInputStream();
//将字节输入流,包装为一个字符流
InputStreamReader isr = new InputStreamReader(is);
//再将该字符流,包装为一个高效字符流
BufferedReader br = new BufferedReader(isr);
String str;
while((str = br.readLine()) != null){
System.out.println("接收到的数据为:" + str);
//给客户端一个反馈信息:
OutputStream os = sk.getOutputStream();
os.write("发送成功".getBytes());
}
ssk.close();
}
// 服务端接收到客户端发来的请求后,给客户端反馈信息
// 客户端接收反馈信息
}
4 案例3
需求:文件上传
(1)客户端从文件中读取数据,将读取的数据发送
(2)服务端将客户端发来的数据,保存在另一个指定文件中
5 案例4
需求:
文件上传成功后,服务端给出上传成功的发聩信息,让客户端知道文件已经发送成功
5.1 客户端代码
package tcp.demo3;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws IOException {
Socket sk = new Socket(InetAddress.getByName("192.168.38.226"),10010);
OutputStream os = sk.getOutputStream();
//将文件中的信息发出:
//1、想要发送一个文件信息,需要先读取这个文件的信息
FileInputStream fis = new FileInputStream("day23/zms.jpeg");
int i;
while((i = fis.read()) != -1){
os.write(i);
}
fis.close();
//当客户端发送完信息之后,要给服务端一个结束的标志
sk.shutdownOutput();
//在此接收反馈
InputStream is = sk.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println(new String(bs,0,len));
sk.close();
}
}
5.2 服务端代码
package tcp.demo3;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ssk = new ServerSocket(10010);
Socket sk = ssk.accept();
InputStream is = sk.getInputStream();
//想要将读取的信息,保存在另一个文件中,需要创建一个文件输出流
FileOutputStream fos = new FileOutputStream("day23/zmscopy.jpeg");
int i;
while((i = is.read()) != -1){
fos.write(i);
}
//服务端给客户端一个反馈信息
OutputStream os = sk.getOutputStream();
os.write("文件上传成功!!!".getBytes());
ssk.close();
fos.close();
}
}
6 案例5
需求:
服务端使用多线程的方式,可以同时接收多个用户发送的文件
客户端代码不变
6.1 服务端代码
package tcp.demo4;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//服务端使用多线程的方式,实现保存文件
//如果同时有多个客户端发送文件,服务端可以分配多个线程分别存储
ServerSocket ssk = new ServerSocket(10010);
//定义一个死循环,持续接收客户端发来的请求
while(true){
Socket sk = ssk.accept();
Task task = new Task(sk);
//客户端发来一个请求,定义一个任务,使用线程来完成该任务
Thread t = new Thread(task);
t.start();
}
}
}
6.2 保存信息任务代码
package tcp.demo4;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
//类型可以定义为保存文件任务
public class Task implements Runnable{
Socket s = null;
public Task(Socket s){
this.s = s;
}
static int x = 0;
@Override
public void run() {
x++;
try {
InputStream is = s.getInputStream();
FileOutputStream fos = new FileOutputStream("day23/zmscopy" + x + ".jpeg");
int i;
while((i = is.read()) != -1){
fos.write(i);
}
fos.close();
OutputStream os = s.getOutputStream();
os.write("文件上传成功".getBytes());
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:案例6的客户端代码与案例5的客户端代码一致