利用网络,实现两台计算机之间的互相联通、交互。
网络编程有两类:
UDP
一种无连接的传输层协议。无连接:指不需要知道对方在不在,只负责发数据传输出去,而对方可能不在,数据便会丢失,所以是不稳定的。
甩代码了!
发送:SendDemo.java
import java.net.*;
class SendDemo{
public static void main(String[] args) throws Exception{
//1.创建UDP服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket(7878);
//2.确定数据,并封装成数据包,DatagramPacket
byte[] buf="nihao hong".getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("10.73.131.122"),10000); //接受对象的ip(这里的ip写的是一个局域网内的ip,可以是本机)及端口
//3.通过socket服务,将现有的数据包发出去,通过send方法
ds.send(dp);
//4.关闭资源,关闭的是使用网络的资源
ds.close();
}
}
接受:ReceiveDemo.java
import java.net.*;
class ReceiveDemo{
public static void main(String[] args) throws Exception{
//1.创建UDP socket,建立端点,设置接受者接收的端口
DatagramSocket ds=new DatagramSocket(10000);
while(true){
//2.定义数据包,用于储存数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//3.通过服务的receive方法将收到数据存入数据包中
ds.receive(dp);
//4.通过数据包的方法获取其中的数据
String ip=dp.getAddress().getHostAddress();//获得ip地址
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();//得到发送端的端口
System.out.println(ip+"::"+data+"::"+port);
}
//5.关闭资源,我希望接收端能够一直接受,于是可以用死循环,但是由于死循环,代码无法走到这里,为图省事就注释了
//ds.close();
}
}
知识点,也是注意点
1. 由于这是UDP,是一种不可靠的连接,所以我们需要先运行接收端,这样才能够接受。
2. 开始在进行测试两台计算机之间的互联时,一直连接不上,我们需要关闭防火墙。
飞Q
听说这是一个能够在局域网内实现通信的工具。
接下来是模拟飞Q的命令行版。
需要使用多线程,同时运行”接受者”和”发送者”。
加上界面话之后,我觉得和飞Q就不远了。
继续甩一对代码:Receiver.java
import java.net.*;
import java.lang.*;
import java.io.*;
class Receiver{
public static void main(String[] args) throws Exception{
Thread t1=new Thread(new Send1());
Thread t2=new Thread(new Rece1());
t1.start();
t2.start();
// ds.close();
}
}
class Send1 implements Runnable{
@Override
public void run(){
try{
DatagramSocket ds=new DatagramSocket();
int len=0;
// byte[] buf=new byte[1024];
String buf;
while(true){
buf=new BufferedReader(new InputStreamReader(System.in,"utf-8")).readLine();
// String str=new String(buf,0,len);
DatagramPacket dp=new DatagramPacket(buf.getBytes(),buf.length(),InetAddress.getByName("10.73.131.122"),10000);
ds.send(dp);
}
}catch (Exception e){
throw new RuntimeException("发送失败");
}
}
}
class Rece1 implements Runnable{
@Override
public void run(){
try{
DatagramSocket ds=new DatagramSocket(10001);
while(true){
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);
System.out.print("对方说:");
System.out.println(new String(dp.getData(),0,dp.getLength(),"utf-8"));
}
}catch (Exception e){
throw new RuntimeException("接受失败");
}
}
}
Sender.java
import java.net.*;
import java.lang.*;
import java.io.*;
class Sender{
public static void main(String[] args) throws Exception{
Thread t1=new Thread(new Send1());
Thread t2=new Thread(new Rece1());
t1.start();
t2.start();
// ds.close();
}
}
class Send1 implements Runnable{
@Override
public void run(){
try{
DatagramSocket ds=new DatagramSocket();
int len=0;
// byte[] buf=new byte[1024];
String buf;
while(true){
buf=new BufferedReader(new InputStreamReader(System.in,"utf-8")).readLine();
// String str=new String(buf,0,len);
DatagramPacket dp=new DatagramPacket(buf.getBytes(),buf.getBytes().length,InetAddress.getByName("10.73.132.176"),10001);
ds.send(dp);
}
}catch (Exception e){
throw new RuntimeException("发送失败");
}
}
}
class Rece1 implements Runnable{
@Override
public void run(){
try{
DatagramSocket ds=new DatagramSocket(10000);
while(true){
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);
System.out.print("对方说:");
System.out.println(new String(dp.getData(),0,dp.getLength(),"utf-8"));
}
}catch (Exception e){
throw new RuntimeException("接受失败");
}
}
}
知识点
1.这里是需要有两台机子相互通信,接收端需要设置义自己接受信息的端口,发送端需要设置自己发送目标的ip地址和端口
2.两台电脑间传输后可能会出现乱码的现象,不过往往是由于编译器不同引起的。大致原因有两个,一个是在键盘键入(System.in)时不同的编译器不同,所以可以使用转换流,将输入的内容的字节,通过指定的字符编码,将键入内容转化为相应编码的字符,再变为字节传输。另一个,接受时,接受的也是字节流,我们也可以用指定的字符编码进行读取。(InputStreamReader)
3.其实一个“发送”涉及输入流和输出流,一个输入流:从键盘得到数据,一个输出流:打包发送。
TCP
一种面向连接的、可靠的、基于字节流的传输层通信协议。需要三次握手。
三次握手,两次是客户端发给服务端的,中间隔了一次服务端发送给客户端。
需求,客户端给服务端发送消息,并能得到服务端的反馈。
甩代码:TcpServer2
import java.io.*;
import java.net.*;
class TcpServer2{
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(10023);
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+".....connection");
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len;
len=in.read(buf);
System.out.println(new String(buf,0,len));
OutputStream out=s.getOutputStream();
out.write("我这收到啦!你也好".getBytes());
s.close();
ss.close();
}
}
TcpClient2java
import java.io.*;
import java.net.*;
class TcpClient2{
public static void main(String[] args) throws Exception{
Socket s=new Socket("10.73.131.122",10023);
OutputStream out=s.getOutputStream();
out.write("你好 服务端".getBytes());
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len;
len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
知识点
由于这是可靠的TCP协议,客户端需要先和服务端建立连接,所以还是需要服务端先运行,当然,如果服务端未运行,或者在客户端运行过程中服务端挂了,那么,在客户端就会抛异常,由于可靠的连接被中断了。
下面的需求是客户端向服务端发送文件,文件传输结束后,给客户端返回传输成功信号
TextServer.java
import java.net.*;
import java.io.*;
class TextServer{
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(10023);
Socket s=ss.accept();
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw=new PrintWriter(new FileWriter("server.txt"),true);
String str;
while((str=br.readLine())!=null){
pw.println(str);
}
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");
pw.close();
s.close();
ss.close();
}
}
TextClient.java
import java.io.*;
import java.net.*;
class TextClient{
public static void main(String[] args) throws Exception{
Socket s=new Socket("10.73.131.122",10023);
BufferedReader in=new BufferedReader(new FileReader("TcpServer2.java"));
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
String str=null;
while((str=in.readLine())!=null){
pw.println(str);
}
s.shutdownOutput();
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String result=br.readLine();
System.out.println(result);
in.close();
s.close();
}
}
这里使用了PrintWriter,好处:字符流和字节流都可以直接写,而且可以实现续写 new PrintWriter(s.getOutputStream(),true) 定义的时候设置。
需求:客户端发送给服务端文字,服务端经过特殊处理(变成全大写返回),返回给客户端,在客户端输出。
TransServer.java
import java.io.*;
import java.net.*;
class TransServer{
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(10023);
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"....connect");
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String str=null;
while((str=br.readLine())!=null){
String newStr=str.toUpperCase();
System.out.println("reply:"+newStr);
out.write(newStr);
out.newLine();
out.flush();
}
s.close();
ss.close();
}
}
TransClient.java
import java.io.*;
import java.net.*;
class TransClient{
public static void main(String[] args) throws Exception{
Socket s=new Socket("10.73.131.122",10023);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String str;
while((str=br.readLine())!=null){
if("over".equals(str)){
break;
}
out.write(str);
out.newLine();
out.flush();
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
String result=in.readLine();
System.out.println(result);
}
br.close();
s.close();
}
}
总结:
当客户端和服务端分离时,我们需要通过网络传输。