63 网络编程(四)——TCP编程

TCP编程

TCP编程是面向连接的数据传输,所以需要时用IO流来建立连接。

用户输出流到服务器,服务器输入流接收数据。

服务器输出流到用户,用户输入流接收。

基本流程

服务器端

  • 创建服务器端:ServerScoekt 对象
  • 阻塞时监听用户接入:accep() 返回Socket对象
  • 建立连接:与返回的Socket对象建立IO流,getInputStream()方法与getOutputStream方法
  • 处理数据
  • 关闭流,关闭Socket对象,关闭服务器(一般不关服务器)

用户端

  • 创建Socket对象:Socket(targetHost,targetPort)
  • 建立连接:创建输出流
  • 传输数据:输入流写
  • 关闭流
  • 关闭Socket对象

基础版本示例

服务器端

package _20191218;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 通过tcp传输数据的服务端,实现的是服务器端
 * @author TEDU
 *
 */
public class TCPServer {
	public static void main(String[] args) throws IOException {
		System.out.println("-----server------");
		//建立服务器
		ServerSocket server = new ServerSocket(6677);
		//阻塞式接收Socket
		Socket client = server.accept();
		//建立连接
		DataInputStream dis = new DataInputStream(client.getInputStream());//选择需要的合适的流,不需要如本文的流
		//接收数据并处理
		Object obj1 = dis.readUTF();
		Object obj2 = dis.readInt();
		Object obj3 = dis.readFloat();
		System.out.println(obj1);
		System.out.println(obj2);
		System.out.println(obj3);
		//关闭流及服务器
		dis.close();
		client.close();
		//server.close()//服务器无需关闭
	}
}

  

用户端

package _20191218;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class TCPClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("-----client------");
		//新建客户端Socket
		Socket client = new Socket("localhost",6677);
		//建立连接
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		//发送数据
		String str = "fuck";
		dos.writeUTF(str);
		dos.writeInt(89);
		dos.writeFloat(213.4f);
		//关闭流和连接
		dos.close();
		client.close();
	}
}

  

测试结果

模拟登陆服务器

客户端与服务器端都可以想对方发送消息。但服务器方是被动响应消息。

服务器端

package _20191218;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器有响应功能,对于用户的请求进行处理,如账号密码均正确,回应登录成功,否则回应登录失败
 * @author TEDU
 *
 */
public class TCPLoginServer {
	public static void main(String[] args) throws IOException {
		System.out.println("服务器端开启");
		//创建服务器端
		ServerSocket server = new ServerSocket(6677);//端口号不能忘
		//阻塞式监听请求:Socket accept()
		Socket client = server.accept();
		//建立连接
		DataInputStream dis = new DataInputStream(client.getInputStream());
		//读取数据
		String str = dis.readUTF();
		String[] datas = str.split("&");
		int count = 0;
		//输出IO流
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		for(String data : datas) {
			if(data.equals("zhanghao")) {
				count++;
			}
			if(data.equals("mima")){
				count++;
			}
		}
		if(count == 2) {
			dos.writeUTF("登陆成功");
		}else {
			dos.writeUTF("登录失败");
		}
		//关闭流、关闭服务器(如果有必要的话)
		dos.close();
		dis.close();
		//server.close();//关闭服务器,如果必要的话
	}
}

  

客户端

package _20191218;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 客户端请求,输入账号密码试图登录服务器
 * @author TEDU
 *
 */
public class TCPLoginClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("用户端开启");
		//创建用户端
		Socket client  = new Socket("localhost",6677);
		System.out.println(client);
		//建立连接
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		//用户输入账号密码
		Scanner scan = new Scanner(System.in);
		System.out.println("请输入账号:");
		String account = scan.nextLine();
		System.out.println("请输入密码:");
		String password = scan.nextLine();
		//传输数据
		dos.writeUTF(account+"&"+password);
//		bw.write(password);
		dos.flush();
		//等待响应
		DataInputStream dis = new DataInputStream(client.getInputStream());
		System.out.println(dis.readUTF());
		//关闭连接(如果需要的话)
		dis.close();
		dos.close();
		client.close();
	}
}

  

测试结果

文件传输至服务器

客户端将文件传输至服务器端。

客户端

package _20191218;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 从客户端传动文件到服务器端
 * @author TEDU
 *
 */
public class FileTCPClient {
	public static void main(String[] args) throws IOException {
		//创建客户端
		Socket client = new Socket("localhost",6687);
		//与本地文件建立连接 IO流
		InputStream is = new FileInputStream(new File("GIF.gif"));
		//与客户端建立连接 IO流
		OutputStream os = new BufferedOutputStream(client.getOutputStream());
		//读取并发送文件
		byte[] datas = new byte[1024*10];
		int len;
		while((len = is.read(datas))!=-1) {//读取文件
			os.write(datas,0,len);//发送文件
		}
		os.flush();
		//关闭流及端
		os.close();
		is.close();
		client.close();
	}
}

  

服务器端

package _20191218;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 接收并存储从客户端传过来的文件
 * @author TEDU
 *
 */
public class FileTCPServer {
	public static void main(String[] args) throws IOException {
		//建立服务器端
		ServerSocket server = new ServerSocket(6687);
		//阻塞式接收Socket
		Socket client = server.accept();
		//与客户端建立连接
		InputStream is = new BufferedInputStream(client.getInputStream());
		//与本地文件建立连接(如文件为空则新建)
		OutputStream os = new FileOutputStream(new File("copy.gif"));
		//读取数据
		byte[] datas = new byte[1024*10];
		int len;
		while((len = is.read(datas))!=-1) {
			//处理数据:写入文件
			os.write(datas,0,len);
		}
		os.flush();
		//关闭流与连接
		os.close();
		is.close();
		server.close();
	}
}

  

先运行服务器端,再运行客户端即可复制完成。

模拟多人登录服务器:服务器多线程

运行一个服务器端,运行多个用户端尝试登录。多开几个控制台。

服务器端

package _20191218;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 支持多用户登录的服务器
 * @author TEDU
 */
public class TCPMultipleLoginServer{
	public static void main(String[] args) {
		System.out.println("服务器开启");
		//新建服务器端
		ServerSocket server = null;
		try {
			server = new ServerSocket(6788);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//声明客户端套机字
		Socket client = null;
		//循环运行请求服务器
		while(true) {
			//客户端套接字
			try {
				client = server.accept();//阻塞接受请求
				System.out.println("有用户尝试登录");
			} catch (IOException e) {
				e.printStackTrace();
			}
			//线程开始(接受客户端发来的数据,做出回应)
			new Thread(new Channel(client)).start();
		}
		
	}
	//写一个内部类,用来实现Runnable接口
	static class Channel implements Runnable{
		//输入流与输出流
		DataInputStream dis;
		DataOutputStream dos;
		//构造方法:传入已经创建好的client
		public Channel(Socket client) {
			//建立连接
			try {
				dis  = new DataInputStream(client.getInputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		public void run() {
			//接受数据
			String[] datas = Receive();
			//响应
			if(datas[0].equals("zhanghao")&&datas[1].equals("mima")) {
				send("登陆成功");
			}else {
				send("登录失败");
			}
			//关闭
			release();
		}
		//接受请求数据
		public String[] Receive() {
			try {
				String[] datas = dis.readUTF().split("&");
				return datas;
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		//响应
		public void send(String response) {
			try {
				dos.writeUTF(response);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//关闭
		public void release() {
			try {
				dos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				dis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

  

用户端

  

package _20191218;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * TCP多用户登录服务器
 */
public class TCPMultipleLoginClient{
	public static void main(String[] args) {
		//创建客户端套接字
		Socket client = null;
		try {
			client = new Socket("localhost",6788);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		new Send(client).send();
		new Receive(client).receive();
	}
	//创建传输数据类
	static class Send{
		//输出流
		DataOutputStream dos;
		//构造方法:传入client
		public Send(Socket client) {
			try {
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//传输数据到服务器的方法
		public void send() {
			Scanner scan = new Scanner(System.in);
			System.out.println("请输入账号:");
			String account = scan.nextLine();
			System.out.println("请输入密码:");
			String password = scan.nextLine();
			try {
				dos.writeUTF(account+"&"+password);
				dos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	//创建接收数据类
	static class Receive{
		//输入流
		DataInputStream dis;
		public Receive(Socket client) {
			try {
				dis = new DataInputStream(client.getInputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//接收方法
		public void receive() {
			try {
				String message = dis.readUTF();
				System.out.println(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

  

posted @ 2019-12-18 11:35  Scorpicat  阅读(176)  评论(0编辑  收藏  举报