小小聊天室,慢慢的回忆啊!(TCP 通信实现)
生活随笔
收集整理的这篇文章主要介绍了
小小聊天室,慢慢的回忆啊!(TCP 通信实现)
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
文章目录
- 前言
- 一、TCP 协议
- 二、 TCP 通信 的实现
- “ 请求- 响应 ” 模式:
- 通过 Socket 的编程顺序:
- 基于TCP协议的Socket编程,实现单向通讯
- 通过数据流改进代码
- 序列化涉及的类和接口(io流知识回顾一下)
- 基于TCP协议的Socket编程,实现双向通讯(通过多线程模拟多个用户请求登录)
- つづく
前言
之前学网络编程这块,就是感觉云里雾里,就想对老师说一句:你说啥呢?这两天学框架,遇到个bug怎么也是解决不了了;这两天还赶上元旦,老师们都放假;进行不下去就回来复习复习吧!看看最头疼的网络编程;重新在看一遍,还真有种知新而温故的感觉!废话不多说,我们看代码;
一、TCP 协议
TCP(Transfer Control Protocol)是面向连接的,所谓面向连接,就是当计算机双方通信时必需经过先建立连接,然后传送数据,最后拆除连接三个过程。二、 TCP 通信 的实现
在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。
“ 请求- 响应 ” 模式:
Socket 类:发送 TCP 消息。
ServerSocket 类:创建服务器。
通过 Socket 的编程顺序:
基于TCP协议的Socket编程,实现单向通讯
代码如下:
服务端
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;/*** 服务器类* */ public class ServerTest {public static void main(String[] args) throws IOException { // 创建serverSocket对象,并指定端口;ServerSocket ss = new ServerSocket(9999); // 利用accept()方法,进行监听 返回一个Socket对象Socket client = ss.accept(); // 接收数据(获取输入流)由于接收到是字节(也就是数字)需要转换成字符read:从输入流读取数据的下一个字节。 InputStream is = client.getInputStream();System.out.println((char)is.read()); // 发出响应(获取输出流)write():将 b.length字节从指定的字节数组写入此输出流。OutputStream os = client.getOutputStream();os.write("收到".getBytes()); // 关闭流if(os!=null) {os.close();}if(is!=null) {is.close();}if(client!=null) {client.close();}}}客户端
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket;/*** 客户类* */ public class ClientTest {public static void main(String[] args) throws IOException { // 创建Socket对象Socket socket = new Socket("192.168.10.102",9999); // 输出数据OutputStream os = socket.getOutputStream(); // write()中的参数只能是,字符类型的os.write('a'); // 接收响应InputStream is = socket.getInputStream();byte[] b = new byte[1024];//中转站,存储读到的数据int len = 0;//读到的个数,当个数为-1时,证明没有数据;if((len=is.read(b))!=-1) { // 利用String的构造方法,将读到的数据输出到控制台System.out.println(new String(b,0,len));} // 关闭流if(is!=null) {is.close();}if(os!=null) {os.close();}if(socket!=null) {socket.close();}}}输出效果
通过数据流改进代码
代码如下:
服务端
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;/*** 服务器类* */ public class ServerTest2 {public static void main(String[] args) throws IOException { // 创建serverSocket对象,并指定端口;ServerSocket ss = new ServerSocket(9999); // 利用accept()方法,进行监听 返回一个Socket对象Socket client = ss.accept(); // 接收数据 获取数据输入流 数据流的参数需要一个字节流DataInputStream dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF()); // 发出响应(获取数据输出流)DataOutputStream dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("收到"); // 关闭流if(dos!=null) {dos.close();}if(dis!=null) {dis.close();}if(client!=null) {client.close();}if(ss!=null) {ss.close();}}}客户端
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket;/*** 客户类* */ public class ClientTest2 {public static void main(String[] args) throws IOException { // 创建Socket对象Socket socket = new Socket("192.168.10.102",9999); // 输出数据 使用数据流进行数据的传输 参数需要一个字节流DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); // writeUTF()是写入的方法;dos.writeUTF("hello world"); // 接收响应DataInputStream dis = new DataInputStream(socket.getInputStream()); // readUTF()是读取数据的方法System.out.println(dis.readUTF()); // 关闭流if(dis!=null) {dis.close();}if(dos!=null) {dos.close();}if(socket!=null) {socket.close();}}}运行效果
序列化涉及的类和接口(io流知识回顾一下)
基于TCP协议的Socket编程,实现双向通讯(通过多线程模拟多个用户请求登录)
创建两个项目(服务器项目、客户端项目)
服务器项目
User类
import java.io.Serializable;public class User implements Serializable{ // 必须要继承Serializable接口 , 否则不能被序列化//为了防止读写的序列化id不同,一定要指定一个固定的序列id 最好不要选择默认的idprivate static final long serialVersionUID = 8251855228567334134L;private String name;private String password;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public static long getSerialversionuid() {return serialVersionUID;}public User(String name, String password) {super();this.name = name;this.password = password;}public User() {super();}}服务器类
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.bjsxt.thread.ServerThread;/*** 服务器类* */ public class Server {public static void main(String[] args) throws IOException, ClassNotFoundException{ // 常见ServerSocket对象; 并指定端口号ServerSocket ss = new ServerSocket(10000); // 监听客户端 accept()方法进行监听 并返回一个Socket对象 // 需要使用循环来监听,不能只监听一次while(true) {Socket client = ss.accept(); // 创建线程对象ServerThread st = new ServerThread(client); // 开启线程new Thread(st).start();}} }添加线程类ServerThread
import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.net.Socket; import com.bjsxt.pojo.User;/*** 将获取每一个客户端都要执行的代码,封装到该类中,并实现Runnable接口,完成多线程* */public class ServerThread implements Runnable{private Socket client;public ServerThread(Socket client) {super();this.client = client;} // 线程中的异常必须处理掉,不能抛出;@Overridepublic void run() { // 想要看到谁在请求登录必须要在线程类的方法中添加 ,如果在服务其中添加会出现main请求登录的字样System.out.println(Thread.currentThread().getName()+"正在请求登录");// 获取对象输入流 需要一个字节流ObjectInputStream ois = null;// 获取数据输出流 响应是字符串 所以用数据输出流 参数需要一个字节流DataOutputStream dos = null;try {ois = new ObjectInputStream(client.getInputStream());// 获取信息 返回一个object对象,将其转换为user对象User user = (User)ois.readObject();// 通过getInetAddress()方法获取InetAddress对象,并获取客户端信息;System.out.println(client.getInetAddress().getHostAddress()+"请求登录"+"\t用户名:"+user.getName()+"\t密码:"+user.getPassword());dos = new DataOutputStream(client.getOutputStream());// 产生响应 判断用户名与密码是否正确String str = null;if("miwa".equals(user.getName())&&"miwa".equals(user.getPassword())) {str = "登录成功";}else {str = "用户名或密码错误";} dos.writeUTF(str);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} // 关闭流 倒着关if(dos!=null) {try {dos.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(ois!=null) {try {ois.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(client!=null) {try {client.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}客户端项目
User类
import java.io.Serializable;public class User implements Serializable{ // 必须要继承Serializable接口 , 否则不能被序列化//为了防止读写的序列化id不同,一定要指定一个固定的序列id 最好不要选择默认的idprivate static final long serialVersionUID = 8251855228567334134L;private String name;private String password;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public static long getSerialversionuid() {return serialVersionUID;}public User(String name, String password) {super();this.name = name;this.password = password;}public User() {super();}}客户端类
import java.io.DataInputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.Socket; import java.util.Scanner;import com.bjsxt.pojo.User;/*** 客户端* */ public class Client {public static void main(String[] args) throws IOException { // 获取Socket对象 并给定服务器地址,以及端口号Socket socket = new Socket("192.168.10.102",10000); // 获取 对象输出流 为了实现登录 ,需要将登录信息封装成对象 参数需要一个字节流对象ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); // 创建用户对象User user = getUser(); // 发送信息 oos.writeObject(user); // 接收响应 响应是字符串类型,所以用数据流接收 参数需要一个字节流DataInputStream dis = new DataInputStream(socket.getInputStream()); // 将响应输出到控制台 readUTF()方法直接返回一个String类型,可以直接输出;System.out.println(dis.readUTF()); // 关闭流if(dis!=null) {dis.close();}if(oos!=null) {oos.close();}if(socket!=null) {socket.close();}}public static User getUser() { // 获取键盘输入对象 Scanner s = new Scanner(System.in);System.out.println("请输入用户名:");String username = s.next();System.out.println("请输入密码:");String password = s.next();return new User(username,password);}}运行效果
つづく
回首看看之前感觉很难的题目;其实也不过如此; 加油,每一个拼搏的你; 谢谢观看; 最后会以一个小小的聊天室项目结束;敬请期待……总结
以上是生活随笔为你收集整理的小小聊天室,慢慢的回忆啊!(TCP 通信实现)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 多线程终极模式:生产者-消费者模式
- 下一篇: 何为主宰