JAVA网络编程TCP实现聊天功能,附在IDEA中同时运行2个或以上相同的java程序
TCP/IP协议, 你一定常常听到,其中TCP(Transmission Control Protocol)称为 传输控制协议,IP(Internet Protocol) 称为网际协议。
事实上TCP/IP协议,是一个协议族,是一个协议的集合。
TCP/IP协议,定义了一整套规则。它定义整个互联网如何连接,如何通信,如何协商的最基础规则。
TCP/IP协议分为五层,分别是应用层、传输层、网络层、数据链路层、物理层。每层都有对应的相关协议,其中TCP和UDP是传输层的两个协议。
理解TCP和UDP
既然他们是传输层的协议,那么他们的作用当然就是用来负责传输数据了。
我们想象一个场景,网络中随意的两端要通信,会采取什么传输方式呢?
可以先想象一下人类之间的通信。
第一种是打电话。我拨通电话你的电话,直到你回答“你好”,我听到声音之后,我们之间才继续进行交谈。
另一个是发短信。我给你的手机号发送一条短信,无法知道你是否收到,然后我就只能等待你的回复了。
其中第一种方式对应TCP,而第二种对应UDP。TCP是需要对方确认的,也就是传输之前需要进行三次握手(传输的两端需要经过三次握手,才开始通信)。UDP着比较粗暴,不论对方什么情况,直接发送,不需要确认过程。
而上图中的看到的,TCP是可靠的,UDP是不可靠的,就是这个意思。
可靠的连接带来的是效率的下降。比如一次网络请求,很大一部分时间其实都是浪费在互相确认的过程当中,资源消耗比较多,保证了数据传输是可靠的,而且传输数据是有序的。不可靠的连接带来的是效率的提升,但可能服务质量有下降。
要摆脱一种人为的误区,不要以为UDP不可靠,就没有应用场景。据说QQ发送数据就是靠UDP发送的,尽管是不可靠的连接,可是还是用了非常多的校验算法保证了数据质量稳定,同也保证了效率。TCP尽管耗时,可是对于稳定性优先的场景,还是应该有限选用TCP,比方浏览器中访问网页用的就是TCP。此外在一些长连接系统里面,比方微信,连接通道应该也是用TCP建立的,由于要维持一条稳定的信息传输通道。
协议是怎么控制,数据包是怎么传输,怎么校验数据的正确性,还有重传特性。这些都是协议中重要的控制过程,在这里不做详解,因为对于实际的产品并没有太大的用。至于如何选定传输数据方式,应该依据场景而定。
安全的东西往往不快,反之亦然。而TCP和UCD之间也是这样:
TCP(传输控制协议)
TCP(传输控制协议)是基于连接的。在正式收发数据之前,必须要与对方建立连接。这之间需要经过'三次握手':
第一次握手的结论是:A的发送能力、B的接收能力正常。
第二次握手的结论是:B的发送能力、A的接收能力正常。
第三次握手的结论是:A的接收、发送能力,B的接收、发送能力都是正常的。
'3次握手'的作用就是 双方都能明确自己和对方的收、发能力是正常的.
UDP(用户数据报协议)
UDP(用户数据报协议)是面向非连接的,不与对方建立连接,而直接把数据报=包发送出去。UDP适用于一次传输少量的数据,对于可靠性要求不高的应用环境。日常生活中使用的ping命令测试主机是否通信正常,事实上'ping'命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,假设数据包是否到达的消息及时反馈回来了,那么网络传输就是正常的。
适用场景
TCP:是全双工、面向连接、可靠的,而且精确控制的协议。主要用于实时性不强,但传输要求高的应用。比方说:网页浏览、文件下载(不是BT、电脑下载)、邮件的发送等场合,这些场景需要TCP协议进行传输。当然,它在网络方面的开销是昂贵的。
UDP:这是一个不可靠的传输协议。由于它不排序所要发送的数据段,不负责这些数据段到达目标的顺序(说一它才不可靠)。它在网络的开销要比TCP小很多,因此UDP适合用在那些实时性强、允许出错的场合。比如说:即时通讯(MSN、QQ),视频、语言等方面。
在IDEA中同时运行2个或以上相同的java程序
在日常编写测试代码时,有时候会需要在idea上同时运行两个及以上相同的java程序,如:想运行两个CLIENTLOGIN测试聊天室效果。
1.点击Edit Configurations…
2.点击Modify options开启下拉框
3.进行如图所示的勾选
4.即可在IDEA中同时运行2个或以上相同的java程序
注:上述为新版本idea设置方法 若你的idea为老版本 按以下步骤进行设置:
1.按照新版本方法(上面方法第一步)进入设置窗口
2.如图进行勾选
1.TCP通信原理
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网路虚拟链路,一旦建立虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。
Java对基于TCP协议的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信!
Java为客户端提供了Socket类,为服务器端提供了ServerSocket类。也就是说,客户端是通过Socket类实现的,而服务端是通过ServerSocket实现的。
2.TCP发送数据的步骤
1.创建客户端的Socket对象(Socket);
2.获取输出流,写数据;
3.使用打印流装饰输出流;
4.释放资源。
按照上述步骤编写的代码如下所示:
package com.example.demo.chat;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) throws IOException {
//创建客户端Socket对象
Socket socket = new Socket("127.0.0.1",9999);
//获取输出流写数据
OutputStream out = socket.getOutputStream();
PrintStream ps = new PrintStream(out);
Scanner scanner = new Scanner(System.in);
String line =null;
while(true){
System.out.println("请说");
line = scanner.nextLine();
if("end".equals(line))
break;
ps.println(line);
}
scanner.close();
ps.close();
out.close();
}
}
3.TCP接收数据的步骤
1.创建服务器端的Socket对象(SocketServer);
2.监听客户端的连接;
3.获取输入流,读数据,并显示在控制台;
4.使用BufferReader装饰输入流对象;
5.释放资源。
按照上述步骤编写的代码如下所示:
package com.example.demo.chat;
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 TcpServer {
public static void main(String[] args) throws IOException {
System.out.println("服务器已启动,正在监听客户端的连接");
ServerSocket serverSocket = new ServerSocket(9999);
//监听客户端的连接
Socket socket = serverSocket.accept();
//获取输入流
InputStream inputStream = socket.getInputStream();
//使用BufferedReader装饰输入流
BufferedReader br=new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line=br.readLine())!=null){
System.out.println("服务器收到的信息:"+line);
}
//释放资源
br.close();
socket.close();
serverSocket.close();
}
}
4.效果展示
客户端执行效果演示:
服务器执行效果演示:
另外:需要注意的是,程序运行的时候需要先启动服务器端的程序,以便于服务器可以首先监听客户端的连接,否则运行程序会报服务器拒绝连接的错误
而由于一般Java程序运行的时候只有一个主线程和一个垃圾回收线程,因为我们程序的客户端的主线程一直在监听用户的输入数据,所以,如果想要实现客户端与服务器的双向聊天,需要使用到多线程来解决,有兴趣的小伙伴可以自己尝试一下。
UDP消息发送
UcdSender:
package com.example.demo.udpchat;
import java.io.IOException;
import java.net.*;
public class UcdSender {
public static void main(String[] args) throws IOException {
//1.建立一个socket
DatagramSocket socket = new DatagramSocket();
//2.建个包
String msg="我想让你给我煮脚";
InetAddress localhost = InetAddress.getByName("127.0.0.1");
int port= 9090;
//数据,数据的长度起始,要发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
//3.发送包
socket.send(packet);
//4.关闭流
socket.close();
}
}
UcdRecived:
package com.example.demo.udpchat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UcdReceiver {
public static void main(String[] args) throws IOException {
//1.开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接受数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);//阻塞接受
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
//关闭连接
socket.close();
}
}