TCP编程
TCP Transmission Control Protocol 传输控制协议,是一种面向连接(两端之间想要数据传输,必须先建立一个持久性的通道)的、可靠(数据不能有丢包的现象)的、基于字节流的传输层通信协议,主要有两个端:1,客户端(Client),主动发出连接的请求2,服务端(Server):被动接受接受客户端的请求,并相应客户端
TCP三次握手
案例1:客户端<------>服务端
需求:客户端键盘录入,服务端输出到控制台
具体实现步骤:
server端
1,建立TCP服务端并且绑定端口,监听端口传来的请求
ServerSocket server =new ServerSocket(10089);
3,通过Server获取一个来自客户端的请求,建立了TCP连接,一个客户端只能有一个Socket
Socket socket =server.accept();//程序阻塞,用于监听客户端的请求
5,读取客户端传来的数据,服务端获取客户端传来的数据流(字节流需要转化为字符流),
BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
6,从客户端读取数据
String line = null;
while((line = br.readLine())!=null) {
System.out.println(line);
}
10, socket.close();//因为这个socket包含了br所以关掉了socket就是关掉了br
client端
2, 创建一个TCP客户端,指定目标IP地址及端口号,已经连上了服务端
Socket client =new Socket("192.168.1.2",10089);
4,客户端向服务端传输的输出流client.getOutputStream()
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
7,从客户端的控制台读取数据
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
8,从控制台读取数据,只要不是"888"就一直读取
String line = null;
while(!(line = br.readLine()).equals("888")) {
bw.write(line);//通过输出流传给服务器
bw.newLine();
bw.flush();
}
9,关流
client.close();
br.close();
package TCP;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient01 {
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
//1,创建一个TCP客户端,指定目标IP地址及端口号,已经连上了服务端
Socket client =new Socket("192.168.1.2",10089);
//客户端获取服务端的输入流client.getInputStream()
//客户端向服务端传输的输出流client.getOutputStream()
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
//2,从客户端的控制台读取数据
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
//3,从控制台读取数据,只要不是"888"就一直读取
String line = null;
while(!(line = br.readLine()).equals("888")) {
bw.write(line);//通过输出流传给服务器
bw.newLine();
bw.flush();
}
//关流
client.close();
br.close();
}
}
package TCP;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer01 {
/**
* 需求:客户端键盘录入,服务端输出到控制台
* @throws IOException
*
*/
public static void main(String[] args) throws IOException {
//1,建立TCP服务端并且绑定端口,监听端口传来的请求
ServerSocket server =new ServerSocket(10089);
System.out.println("服务端开启.........");
//2,通过Server获取一个来自客户端的请求,建立了TCP连接,一个客户端只能有一个Socket
Socket socket =server.accept();//程序阻塞,用于监听客户端的请求
System.out.println("server:获取一个客户端请求(链接)。。。。");
//3,读取客户端传来的数据
//服务端获取客户端传来的数据流(字节流需要转化为字符流)socket.getInputStream()
BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4,从客户端读取数据
String line = null;
while((line = br.readLine())!=null) {
System.out.println(line);
}
socket.close();//因为这个socket包含了br所以关掉了socket就是关掉了br
}
}
案例2:
需求:从客户端上传文件给服务端
先画下流的流向图
注意上面的箭头不代表方向,只是代表一个通道而已,这个通道是双向的,如果出现两个通道就要关掉其中一个
代码
public class TCPServer02 {
public static void main(String[] args) throws IOException {
//1,建立TCP服务并且绑定端口,监听端口传来的请求
ServerSocket server =new ServerSocket(5678);
System.out.println("Server:服务器开启。。。。");
//2,通过server获取一个来自客户端的请求,建立TCP的连接
Socket socket =server.accept();
System.out.println("Server:接受一个连接。。。。");
//3,读取客户端传来的数据,服务端获取客户端传来的数据流(字节流需要转化为字符流),
BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4,获取文件的输出流
BufferedWriter b =new BufferedWriter(new FileWriter("copytest.txt"));
//5,获取服务端的输出流,向客户端做一个回应
BufferedWriter bb =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line =null;
//4,从客户端读取数据
while((line =br.readLine())!=null) {
b.write(line);
b.newLine();
b.flush();
}
System.out.println("文件上传成功,服务器关闭。。。。");
//关闭server输入流,服务端和客户端不能同时存在两个通道流
socket.shutdownInput();
bb.write("文件上传完毕");
bb.newLine();
bb.flush();
b.close();
socket.close();
}
}
public class TCPClient {
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
//1,创建一个TCP客户端,指定目标IP及端口号,已经连上了服务端
Socket client =new Socket("192.168.1.2",5678);
//2,从文件中获取输入流
BufferedReader br =new BufferedReader(new FileReader("test.txt"));
//3,客户端向服务端的输出流
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
//4,获取服务端的相应
BufferedReader bbr =new BufferedReader(new InputStreamReader(client.getInputStream()));
String line =null;
//5,从文件中读取数据,只要读到的不是空,就一直读
while((line = br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭Socket的输出流
client.shutdownOutput();
System.out.println(bbr.readLine());
br.close();
client.close();
}
案例三:
需求:多个客户端向服务端发送消息,服务端再向客户端响应
步骤:
server
1,建立TCP链接并且绑定端口
ServerSocket server =new ServerSocket(10098);
System.out.println("sever is running");
2,服务端一直监听端口并且创建与客户端的连接
while(true){
Socket socket =server.accept();
System.out.println("a client is connnected")
3,开启一个子线程来处理与客户端的交流(只要客户端代码运行一次,就开启一个客户端(线程))
Handle t =new Handle(socket);
Thread t =new Thread(t);
t.start();
}
4,写线程的具体任务
class Handle implements Runnable{
private Socket socket;
public Handle(Socket socket){
this.socket = socket;
}
public void run(){
//从客户端获取的输入流
InputStream in =socket.getInputStream();
//到客户端的输出流
OutputStream out =socket.getOutputStream();
hander(in,out);
}
}
5,实现hander()方法
public void hander(InputStream in,OutputStream out){
BufferedReader br =new BufferedReader(new InputStreamReader(in));
BufferedWriter bw =new BufferedWriter(new OutputStream(out));
6,服务端先向客户端发送一个消息
bw.write("hello\n");
bw.flush();
7,一直与客户端交流
while(true){
String s =br.readLine();//读取从客户端发来的消息
if(s.equals("888")){
bw.write("888");
bw.flush();
break;
}
bw.write("ok"+s+"\n")
bw.flush();
}
socket.close();
client:
1,创建一个TCP链接并且绑定端口,连上服务器
Socket socket =new Socket("192.168.1.2",10098);
InputStream in =socket.getInputStream();
OutputStream out =socket.getOutputStream();
2,客户端与服务器数据进行交互
hander(in,out);
3,关流
socket.close();
System.out.println("client is disconnected ");
4,重写hander()函数
public static void hander(InputStream in,OutputStream out){
BufferedReader br =new BufferedReader(new InputStreamReader(in));//从客户端进来的输入流
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(out));//从客户端出去的流
5,客户端从控制台读入数据
Scanner scanner =new Scanner (System.in);
6,从服务器读取数据
System.out.println("server"+br.readLine());
while(true){
System.out.print("client>>>>>");
String s =scanner.nextLine();
bw.write(s);
bw.newLine();
bw.flush();
String resp =br.readLine();
System.out.println("<<<"+resp);
if(resp.equals("888")){
break;
}
这样就实现了多个客户端与一个服务器进行数据传输
public class TCPServer {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//1,建立TCP链接并且绑定端口
ServerSocket server =new ServerSocket(10088);
System.out.println("sever is running");
//2,服务端一直监听端口并且创建与客户端的连接
while(true) {
Socket socket =server.accept();
System.out.println("a clent is connected");
//3,开启一个子线程来处理与客户端的交流
Handle t =new Handle(socket);
Thread t1 =new Thread(t);
t1.start();
}
}
}
class Handle implements Runnable{
private Socket socket;
public Handle(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从客户端获取的输入流
InputStream in =socket.getInputStream();
//到客户端的输出流
OutputStream out =socket.getOutputStream();
hander(in,out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void hander(InputStream in, OutputStream out) throws IOException {
// TODO Auto-generated method stub
BufferedReader br =new BufferedReader(new InputStreamReader(in));
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(out));
//6,服务端先向客户端发送一个消息
bw.write("hello\n");
bw.flush();
//7,一直与客户端交流
while(true){
String s =br.readLine();//读取从客户端发来的消息
if(s.equals("888")){
bw.write("888");
bw.flush();
break;
}
bw.write("ok"+s+"\n");
bw.flush();
}
socket.close();
}
}
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
//1,创建一个TCP链接并且绑定端口,连上服务器
Socket socket =new Socket("192.168.1.2",10088);
InputStream in =socket.getInputStream();
OutputStream out =socket.getOutputStream();
//2,客户端与服务器数据进行交互
hander(in,out);
//3,关流
socket.close();
System.out.println("client is disconnected ");
}
private static void hander(InputStream in, OutputStream out) throws IOException {
// TODO Auto-generated method stub
BufferedReader br =new BufferedReader(new InputStreamReader(in));//从客户端进来的输入流
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(out));//从客户端出去的流
//5,客户端从控制台读入数据
Scanner scanner =new Scanner (System.in);
//6,从服务器读取数据
System.out.println("server"+br.readLine());
while(true){
System.out.print("client>>>>>");
String s =scanner.nextLine();
bw.write(s);
bw.newLine();
bw.flush();
String resp =br.readLine();
System.out.println("<<<"+resp);
if(resp.equals("888")){
break;
}
}
}
运行结果:
案例四:
需要:实现多客户向服务端传递文件
步骤:
server:
1,建立TCP链接并且绑定端口
ServerSocket server =new ServerSocket(10086);
System.out.println("sever is running");
2,服务端一直监听端口并且创建与客户端的连接
while(true){
Socket socket =server.accept();
System.out.println("a client is connnected")
3,开启一个子线程来处理与客户端的交流(只要客户端代码运行一次,就开启一个客户端(线程))
ReceivedFileTask task =new ReceivedFileTask(socket);
Thread t =new Thread(t);
t.start();
}
4,写线程的具体任务
class ReceivedFileTask implements Runnable{
private Socket socket;
public ReceivedFileTask(Socket socket){
this.socket = socket;
}
public void run(){
//获取从客户端来的输入流(字节)
BufferedInputStream in = null;
//获取服务端的输出流(向客户端反馈消息) 字符
BufferedWriter out = null;
//获取文件的字节输出流
BufferedOutputStream bos = null;
in = new BufferedInputStream(socket.getInputStream());
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String fileName = FileNameUtil.getName(); //文件名字如果客户端没有上传 服务端自定义
bos = new BufferedOutputStream(new FileOutputStream(fileName));
//从服务端的输入流获取数据写入文件中
byte[] buf = new byte[1024];
int len =0;
while ((len = in.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
//向服务端反馈
out.write("over");
out.flush();
System.out.println("a file has been received.......");
5,关流
socket.close();
if(bos!=null){
bos.close();
}
package part01.网络编程;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient04 {
public static void main(String[] args) {
String ip = "172.16.80.51";
UpdateFileTask task1 = new UpdateFileTask(ip, "任务1", "周杰伦 - 彩虹.m4a");
UpdateFileTask task2 = new UpdateFileTask(ip, "任务2", "周杰伦 - 超跑女神.m4a");
UpdateFileTask task3 = new UpdateFileTask(ip, "任务3", "周杰伦 - 超人不会飞.m4a");
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task2);
Thread t3 = new Thread(task3);
t1.start();
t2.start();
t3.start();
}
}
class UpdateFileTask implements Runnable {
private String ip;
private String taskName;
private String fileName;
public UpdateFileTask(String ip, String taskName, String fileName) {
this.ip = ip;
this.taskName = taskName;
this.fileName = fileName;
}
@Override
public void run() {
System.out.println(taskName + " start......");
Socket socket = null;
//获取文件的字节输入流
BufferedInputStream bis = null;
//获取客户端向服务端写出数据的输出流
BufferedOutputStream out = null;
//获取客户端读取服务端传来的输入流
BufferedReader in;
try {
socket = new Socket(ip,10086);
bis = new BufferedInputStream(new FileInputStream(fileName));
out = new BufferedOutputStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
byte[] buf = new byte[1024];
int len = 0;
while ((len = bis.read(buf)) != -1) {
out.write(buf, 0, len);
out.flush();
}
//获取服务端的响应
socket.shutdownOutput();
String resp = in.readLine();
System.out.println(taskName + resp);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package part01.网络编程;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 多客户端上传文件 服务端接收
* */
public class TCPServer04 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(10086);
System.out.println("server running......");
while (true) {
Socket socket = server.accept();
System.out.println("a client connnected......");
ReceivedFileTask task = new ReceivedFileTask(socket);
Thread t = new Thread(task);
t.start();
}
}
}
class FileNameUtil {
private static int number = 1;
public synchronized static String getName() {
return "music" + number++ + ".mp3";
}
}
class ReceivedFileTask implements Runnable {
private Socket socket;
public ReceivedFileTask(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//获取服务端的输入流(从客户端来的) 字节
BufferedInputStream in = null;
//获取服务端的输出流(向客户端反馈消息) 字符
BufferedWriter out = null;
//获取文件的字节输出流
BufferedOutputStream bos = null;
try {
in = new BufferedInputStream(socket.getInputStream());
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String fileName = FileNameUtil.getName(); //文件名字如果客户端没有上传 服务端自定义
bos = new BufferedOutputStream(new FileOutputStream(fileName));
//从服务端的输入流获取数据写入文件中
byte[] buf = new byte[1024];
int len =0;
while ((len = in.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
//向服务端反馈
out.write("over");
out.flush();
System.out.println("a file has been received.......");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}