谈谈java网络编程套路

614 阅读8分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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类来描述;

计算机网络中两台电脑之间进行数据传输前提:

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

\