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(); } } } }