一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
说到Java网络编程,你会想到什么呢?网络编程应该这么写呢?不用着急,一篇文章教会你
观看须知:了解流参考文章谈谈io流&&文件复制的几种方法 - 掘金 (juejin.cn)
啥是网络编程
网络编程其实是Socket编程
1、Socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议; 应用程序可以通过套接字发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作;套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信;
2、Socket原理
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字,即就是Socket=IP+端口号;
通信的两端都有Socket、网络通信其实就是Socket间的通信、数据在两个Socket间通过IO传输;
3、Java如何进行网络编程
UDP协议使用的Socket,Java提供了DatagramSocket类来描述;
TCP协议使用的Socket,Java使用了Socket类来描述;
计算机网络中两台电脑之间进行数据传输前提:
a电脑给b电脑发送数据 不但需要知道b的ip地址 还需要声明接受数据的软件 .
a电脑必须获取b电脑的ip地址 .
a电脑通过互联网指定b的ip地址 ,在电脑里面是32为2进制,为了人阅读方便变成了例如 122.222.0.103
b电脑中有n个软件可以接受数据 不同软件解析数据的格式(不同软件之间制定的数据传输协议不同)是不同的
IP地址:InetAddress: 网络中设备的标识,不易记忆,可用[主机名]
端口号:用于标识进程的[逻辑地址],不同进程的标识 ;
传输协议:通讯的规则常见协议:TCP,[UDP]
开发第一个网络编程
模板
1.客户端建立连接 ;服务端准备服务(ip[默认本机]:端口)
Socket socket=new Socket("ip名字",端口号)
2.通过socket生成inputstream/outputstream(准备发送数据)
inputStream in=socket.getInputStream();
outputStream in=socket.getoutputStream();
3.使用inputstream/outputstream进行发送、接受数据
in = socket.getInputStream();
//带缓冲区的字符流(字节流-转换流-字符流)
reader = new BufferedReader(new InputStreamReader(in));
String info = null ;
while( (info=reader.readLine()) != null
){
System.out.println("I am server,接受到客户端信息是:" + info);
}
socket.shutdownInput();
4.关闭inputstream/outputstream、socket
过程
先在server服务端编写
public static void main(String[] args) {
try {
serversocket=new ServerSocket(8888);
System.out.println("端口号已经出现了");
}catch(...)
}
然后去client客户端编写
public static void main(String[] args) {
try {
Socket socket=new Socket("localhost",8888);
System.out.println("客户端链接成功了");
}catch(...)
}
然后回到server里编写
public static void main(String[] args) {
try {
serversocket=new ServerSocket(8888);
System.out.println("端口号已经出现了");
System.out.println("开始链接");
socket=serversocket.accept();
System.out.println("链接成功");
}catch(...)
}
这个时候可以运行来测试,是不是链接成功了
然后开始发送和接受数据
比如客户端发送消息
public static void main(String[] args) {
try {
Socket socket=new Socket("localhost",8888);
System.out.println("客户端链接成功了");
OutputStream out=socket.getOutputStream();
out.write("hello,this,test".getBytes());
// 把管道里面流的数据刷到内存
socket.shutdownOutput();
}catch(...)
}
服务端接收消息
public static void main(String[] args) {
try {
serversocket=new ServerSocket(8888);
System.out.println("端口号已经出现了");
System.out.println("开始链接");
Socket socket=serversocket.accept();
System.out.println("链接成功");
// 通过socket生成io流,准备接受数据
Inputstream in=socket.getInputStream();
// 根据前面io,我们可以new字符数组,或者变成带缓冲区的
// 字节-》转换-》字符
reader=new BufferedReader(new InputStreamReader(in));
String into=null;
while((into=reader.readLine())!=null) {
System.out.println("接受的消息是:::"+into);
}
socket.shutdownInput();
}catch(...)
}
下面可以直接finally关闭流,也可以添加应该服务端发送数据的 服务端
public static void main(String[] args) {
try {
serversocket=new ServerSocket(8888);
System.out.println("端口号已经出现了");
System.out.println("开始链接");
Socket socket=serversocket.accept();
System.out.println("链接成功");
// 通过socket生成io流,准备接受数据
Inputstream in=socket.getInputStream();
// 根据前面io,我们可以new字符数组,或者变成带缓冲区的
// 字节-》转换-》字符
reader=new BufferedReader(new InputStreamReader(in));
String into=null;
while((into=reader.readLine())!=null) {
System.out.println("接受的消息是:::"+into);
}
socket.shutdownInput();
//服务端做出反馈
Outputstream out = socket.getOutputStream();
out.write("welcome client....".getBytes());
socket.shutdownOutput();
}catch(...)
}
客户端接收
public static void main(String[] args) {
try {
Socket socket=new Socket("localhost",8888);
System.out.println("客户端链接成功了");
OutputStream out=socket.getOutputStream();
out.write("hello,this,test".getBytes());
// 把管道里面流的数据刷到内存
socket.shutdownOutput();
// 接收服务端返回
in=socket.getInputStream();
// 根据前面io,我们可以new字符数组,或者变成带缓冲区的
// 字节-》转换-》字符
reader=new BufferedReader(new InputStreamReader(in));
String into=null;
while((into=reader.readLine())!=null) {
System.out.println("收到的服务消息是:::"+into);
}
socket.shutdownInput();
}catch(...)
}
最后在finally里面关闭流
完整代码
server
package 网络通信;
//1.客户端建立链接
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class damo1Server {
public static void main(String[] args) {
InputStream in=null;
BufferedReader reader=null;
OutputStream out=null;
ServerSocket serversocket=null;
Socket socket=null;
//服务端准备链接
try {
serversocket=new ServerSocket(8888);
System.out.println("端口号已经出现了");
// 监听客户端需求
System.out.println("开始链接");
socket=serversocket.accept();
System.out.println("链接成功");
// 通过socket生成io流,准备接受数据
in=socket.getInputStream();
// 根据前面io,我们可以new字符数组,或者变成带缓冲区的
// 字节-》转换-》字符
reader=new BufferedReader(new InputStreamReader(in));
String into=null;
while((into=reader.readLine())!=null) {
System.out.println("接受的消息是:::"+into);
}
socket.shutdownInput();
// 服务端返回消息
out=socket.getOutputStream();
out.write("用户你好,我已经收到消息了".getBytes());
// 把管道里面流的数据刷到内存
socket.shutdownOutput();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(reader!=null)reader.close();
if(out!=null)out.close();
if(in!=null)in.close();
if(socket!=null)socket.close();
if(serversocket!=null)serversocket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
client
package 网络通信;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class demo1client {
public static void main(String[] args) {
InputStream in=null;
BufferedReader reader=null;
OutputStream out=null;
Socket socket=null;
try {
socket=new Socket("localhost",8888);
System.out.println("客户端链接成功了");
// 客户端发送信息,产生io流
out=socket.getOutputStream();
out.write("hello,this,test".getBytes());
// 把管道里面流的数据刷到内存
socket.shutdownOutput();
// 接收服务端返回
in=socket.getInputStream();
// 根据前面io,我们可以new字符数组,或者变成带缓冲区的
// 字节-》转换-》字符
reader=new BufferedReader(new InputStreamReader(in));
String into=null;
while((into=reader.readLine())!=null) {
System.out.println("收到的服务消息是:::"+into);
}
socket.shutdownInput();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(reader!=null)reader.close();
if(out!=null)out.close();
if(in!=null)in.close();
if(socket!=null)socket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
对象流
网络传递一个对象: 1.将要传递的对象序列化
2.使用对象流(ObjectInputStream/ObjectOutputStream
关键:接收数据变成
//接受发来的对象
in = socket.getInputStream();
//对象流
ois = new ObjectInputStream(in);
try {
Student student = (Student)ois.readObject();//读取对象
System.out.println(student);
socket.shutdownInput();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
发送数据变成
out = socket.getOutputStream();
//将OutputStream转为对象流
oos = new ObjectOutputStream(out) ;
oos.writeObject( student );//发送对象
socket.shutdownOutput();
完整代码
1.实体对象
package 网络通信;
import java.io.Serializable;
//要传递的对象序列化
public class demo2Student implements Serializable{
private int sid;
private String sname;
private int age;
public demo2Student() {
}
@Override
public String toString() {
return "demo2Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
}
public demo2Student(int sid, String sname, int age) {
super();
this.sid = sid;
this.sname = sname;
this.age = age;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2server
package 网络通信;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class demo2server {
public static void main(String[] args) {
ServerSocket serversocket=null;
Socket socket=null;
InputStream in=null;
ObjectInputStream ois=null;
try {
serversocket =new ServerSocket(8888);
socket=serversocket.accept();
// 接收对象
in= socket.getInputStream();
// 对象流
ois=new ObjectInputStream(in);
demo2Student stu=(demo2Student)ois.readObject();
System.out.println(stu);
socket.shutdownInput();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
// if(out!=null)out.close();
try {
if(ois!=null)ois.close();
if(in!=null)in.close();
if(socket!=null)socket.close();
if(serversocket!=null)serversocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3.client
package 网络通信;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class demo2client {
public static void main(String[] args) {
Socket socket=null;
OutputStream out=null;
ObjectOutputStream oos=null;
try {
socket =new Socket("localhost", 8888);
// 客户端发送数据
demo2Student stu=new demo2Student(1001,"张三",20);
out=socket.getOutputStream();
// 把输出流变成对象
oos=new ObjectOutputStream(out);
oos.writeObject(stu);
socket.shutdownOutput();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(oos!=null)oos.close();
// if(in!=null)in.close();
if(out!=null)out.close();
if(socket!=null)socket.close();
// if(serversocket!=null)serversocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
多服务端问题
思路:客户端代码不变;服务端:每当有一个客户端,就开启一个新线程去处理(每个线程专门处理一个客户端对象)。
服务端线程
package demo03;
import java.io.*;
import java.net.Socket;
public class ServerThread extends Thread{
Socket socket ;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
InputStream in =null ;
ObjectInputStream ois = null ;
OutputStream out = null ;
try {
//接受客户端数据(客户端—>服务端)
in = socket.getInputStream();
ois = new ObjectInputStream(in) ;
Student student = (Student)ois.readObject() ;
System.out.println(student);
socket.shutdownInput();
//给客户端反馈(服务端->客户端)
out = socket.getOutputStream();
out.write("已收到....".getBytes());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally {
try {
out.close();
ois.close();
in.close();
socket.close(); ;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务端
package demo03;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8888) ;
while(true) {
Socket socket = serverSocket.accept();//阻塞,接受客户端请求
ServerThread serverThread = new ServerThread(socket) ;
serverThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
package demo03;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class MyClient {
public static void main(String[] args) {
Socket socket = null ;
OutputStream out = null ;
ObjectOutputStream oos = null ;
try {
socket = new Socket("localhost",8888) ;
Student student = new Student(1001,"zs",23);
out = socket.getOutputStream();
//将OutputStream转为对象流
oos = new ObjectOutputStream(out) ;
oos.writeObject( student );//发送对象
socket.shutdownOutput();
//接受服务端的反馈
InputStream in = socket.getInputStream();
byte[] buf = new byte[100] ;
in.read(buf) ;
System.out.println("接收到的服务端反馈:" + new String(buf) );
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
if(oos!=null) oos.close();
if(out!=null) out.close();
if(socket!=null) socket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
\