java网络编程总结
最近在研究kafka的源码,先说一下感触,虽然kafka不是用java写的,只是提供了java的客户端,但是单纯这个客户端的代码已经让我焦头烂额了,可以很肯定的说现在的我真的是太菜了,需要学习的东西太多,不过乐观点的说我的成长空间也很大,而且读源码真的是非常好的学习机会,很推荐有时间的朋友们读一个框架的源码。通过读源码我发现了很多的不足,这里仅仅记录一些关于java网络编程的,顺便将以前总结的关于网络编程的笔记汇总一下。关于kafka的源码中的补充的知识也会逐渐添加进来。
1、InetAddress类,这个出现于kafkaProducer的源码中。这个类表示的是ip地址的详细信息,通过它既可以获得域名也可以获得ip地址,但是这个类是不含有端口号的。
InetAddress没有构造方法,只能通过类中的静态方法获得实例,既可以通过getBy***方法获得指定域名的ip也可以通过getLocalhost来获得本机的ip。
2、InetSocketAddress类,这个是在对InetAddress类的补充,在ip地址的基础上添加了端口号。
InetSocketAddress的构造方法很简单,既可以使用域名+端口号,也可以使用InetAddress + 端口号。
数据的传输:TCP(transfer control protocal,传输控制协议) UDP(user datagram protocal)
TCP是面向连接的传输,必须要建立起连接之后才可以进行通信。tcp的连接的建立需要三次握手,先是客户端发送SYN同步报文,然后服务器端发送ACK确认报文即SYN同步报文,最后客户端再次发送ACK确认报文连接即建立。tcp就像是打电话,通话双方都必须拿起电话才可以讲话。tcp的这个特性决定了他的安全性,消息不会丢失,但是效率去相对较低。
UDP一种无连接的传输层协议,提供面向事物的简单不可靠信息传送服务。他是非面向连接的,即不用连接也能通信,所以存在传输不可靠的特点,就像是发送短信,即使另一方没有开机也可以发,而且发送方无法得知是否已经发送。
在java的网络编程中,UDP使用的是DatagramSocket + DatagramPacket,DatagramSocket是用来发送和接收DataGramPacket(数据报)的对象,服务器端和客户端都使用的是DatagramSocket,DatagramPacket就是数据报,里面含有要发送的信息和此数据报要发送到的目的地的ip地址和端口号,在服务器端和客户端的数据报的建立方法不同。 TCP使用的是:ServerSocket + Socket,ServerSocket是用来监听访问的,每当有新的请求来时服务器端就会建立socket用来和此进行会话。
UDP的编程实例:
//这是服务器端的代码 public class UDPServer { public static void main(String[] args) throws IOException { DatagramSocket server = new DatagramSocket(9999); byte[] container = new byte[1024]; //这个是用来接受数据的信息报 DatagramPacket pack = new DatagramPacket(container, container.length); server.receive(pack);//程序执行到这的时候就会阻塞 byte[] data = pack.getData(); String dataStr = new String(data, 0, pack.getLength()); System.out.println(dataStr); server.close(); } } //这是客户端的代码 public class UDPClient { public static void main(String[] args) throws IOException { DatagramSocket cli = new DatagramSocket(8888); byte[] data = "hello world".getBytes(); //这个是用来发送的信息报的,所以必须指定此数据报的发送的ip和端口 DatagramPacket packet = new DatagramPacket(data, data.length, new InetSocketAddress("localhost", 9999)); cli.send(packet);; cli.close(); } }可以在不运行服务器端的情况下运行客户端,并且不会报错,因为UDP不是面向连接的,所以不用建立连接,不过这样也就会丢失数据报。所以如果要看到实验的结果必须要先运行服务器端(服务器端在执行到receive时就会阻塞),然后再运行客户端。
除了发送字符串类之外,也可以发送java类,先用ObjectOutputStream将java类转换为byte[],然后发送byte[],再接收端用ObjectInputStream将接受到的byte[]转化为指定的java类。
public class UDPServer { public static void main(String[] args) throws IOException, ClassNotFoundException { DatagramSocket server = new DatagramSocket(9999); byte[] container = new byte[1024]; //这个是用来接受数据的信息报 DatagramPacket pack = new DatagramPacket(container, container.length); server.receive(pack); byte[] data = pack.getData(); ByteArrayInputStream stream = new ByteArrayInputStream(data, 0, pack.getLength()); ObjectInputStream in = new ObjectInputStream(stream); UDPClient c = (UDPClient) in.readObject(); System.out.println(c.name); server.close(); } } public class UDPClient implements Serializable { private static final long serialVersionUID = 5810472933704265330L; public String name = "hello world"; public static void main(String[] args) throws IOException { DatagramSocket cli = new DatagramSocket(8888); UDPClient c = new UDPClient(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(stream); out.writeObject(c); byte[] data = stream.toByteArray(); //这个是用来发送的信息报的,所以必须指定此数据报的发送的ip和端口 DatagramPacket packet = new DatagramPacket(data, data.length, new InetSocketAddress("localhost", 9999)); cli.send(packet);; cli.close(); } }
TCP编程实例
服务器端:
public class Server { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(9999); while(true){ Socket socket = server.accept();// System.out.println("有请求来了"); new Thread(new SocketTask(socket)).start(); } } } class SocketTask implements Runnable{ Socket socket = null; public SocketTask(Socket socket) { if(socket == null){ throw new IllegalArgumentException(); } this.socket = socket; } public void run() { try { InputStream inputStream = socket.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); String msg = reader.readLine(); System.out.println(msg); socket.close(); } catch (Exception e) { e.printStackTrace(); } } }
说明:ServerSocket的accept方法会阻塞,这里采用的办法是无限循环,只要有一个请求来了就会建立一个线程去处理这个这次请求,将返回的socket实例加入到这个线程中去。
客户端:
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost",9999); OutputStream outStream = socket.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outStream,"UTF-8")); writer.write("中国"); writer.close(); socket.close(); } }
在TCP中,如果先启动客户端的话就会报错,因为TCP是面向连接的,必须现有连接才可以进行通信,而UDP则相反。如果想得到预期的效果就必须先启动服务器端。
这几个小例子都很简单,最初学java的时候经常写,重新写一遍的原因就是复习一下,做到温故知新,熟能生巧。