1,网络基础和软件编程java
软件编写人员不须要了解太多的网络知识(基础仍是须要的);软件编写人员主要抓住几点就能够作网络编程;编程
1,信息传输都是0和1的传输;浏览器
2,信息传输须要遵守网络协议;(底存的网络协议 和传输格式协议)服务器
3,抓住传输协议的要点(如 协议的用途 简要协议实现方式)网络
4,IOapp
注:有很软件编程人员一般都不知道什么是协议,抓不到协议重点;有些时候在对接的时候问他们使用的什么协议,统一回复tcp/ip协议;这让我非常蛋疼;dom
补充:OSI(Open System Interconnection)开放式互联协议模型
socket
分为7层:1.物理层 2.数据链路层 3.网络层 4.传输层 5.会话层 6.表示层 7.应用层jsp
TCP/IP协议模型:
tcp
分为4层: 1.网络接口层,2.互联网层 3.传输层 4.应用层
协议都是分层的,咱们经常使用的都是应用层协议;如htpp协议;
什么是协议?协议规定了咱们在网络传输中的格式样板;
2,Java网络编程Socket
1,什么是Socket
网络上的两个程序经过一个双向的通信链接实现数据的交换,这个双向链路的一端称为一个Socket。Socket一般用来实现客户方和服务方的链接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号惟一肯定。
可是,Socket所支持的协议种类也不光TCP/IP一种,所以二者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
2,Socket通信的过程
Server端Listen(监听)某个端口是否有链接请求,Client端向Server 端发出Connect(链接)请求,Server端向Client端发回Accept(接受)消息。一个链接就创建起来了。Server端和Client 端均可以经过Send,Write等方法与对方通讯。
对于一个功能齐全的Socket,都要包含如下基本结构,其工做过程包含如下四个基本的步骤:
(1) 建立Socket;
(2) 打开链接到Socket的输入/出流;
(3) 按照必定的协议对Socket进行读/写操做;
(4) 关闭Socket.(在实际应用中,并未使用到显示的close,虽然不少文章都推荐如此,不过在个人程序中,可能由于程序自己比较简单,要求不高,因此并未形成什么影响。)
3,建立Socket
建立Socket
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向链接的客户端和服务端。这是两个封装得很是好的类,使用很方便。其构造方法以下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr, int localPort)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddress bindAddr)
其中address、host和port分别是双向链接中另外一方的IP地址、主机名和端 口号,stream指明socket是流socket仍是数据报socket,localPort表示本地主机的端口号,localAddr和 bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既能够用来建立serverSocket又可 以用来建立Socket。count则表示服务端所能支持的最大链接数。例如:学习视频网 http://www.xxspw.com
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
注意,在选择端口时,必须当心。每个端口提供一种特定的服务,只有给出正确的端口,才 能得到相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 因此咱们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。
在建立socket时若是发生错误,将产生IOException,在程序中必须对之做出处理。因此在建立Socket或ServerSocket是必须捕获或抛出例外。
package com.dom.socket; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.ServerSocket; import java.net.Socket; public class ServiceDom { public static void main(String[] args){ try { ServerSocket server = new ServerSocket(8082); Socket socket = server.accept(); //得到服务端套接字的输入输出流 Reader reader = new InputStreamReader(socket.getInputStream()); char chars[] = new char[64]; int len; StringBuilder sb = new StringBuilder(); while ((len=reader.read(chars)) != -1) { sb.append(new String(chars, 0, len)); } System.out.println("from client: " + sb); reader.close(); socket.close(); server.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.dom.socket; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.Socket; import java.net.UnknownHostException; public class ClientDom { public static void main(String [] ags){ try { Socket socket = new Socket("127.0.0.1",8082); Writer writer = new OutputStreamWriter(socket.getOutputStream()); writer.write("my socket dom"); writer.flush(); writer.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
使用socket实现http协议传输消息
import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; /** * 一个简单的HTTP客户端,发送HTTP请求,模拟浏览器 * 可打印服务器发送过来的HTTP消息 */ public class SimpleHttpClient { private static String encoding = "GBK"; public static void main(String[] args) { try { Socket s = new Socket(InetAddress.getLocalHost(), 8080); OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream()); StringBuffer sb = new StringBuffer(); sb.append("GET /HttpStream/gb2312.jsp HTTP/1.1\r\n"); sb.append("Host: localhost:8088\r\n"); sb.append("Connection: Keep-Alive\r\n"); sb.append("\r\n"); osw.write(sb.toString()); osw.flush(); //--输出服务器传回的消息的头信息 InputStream is = s.getInputStream(); String line = null; int contentLength = 0;//服务器发送回来的消息长度 // 读取全部服务器发送过来的请求参数头部信息 do { line = readLine(is, 0); //若是有Content-Length消息头时取出 if (line.startsWith("Content-Length")) { contentLength = Integer.parseInt(line.split(":")[1].trim()); } //打印请求部信息 System.out.print(line); //若是遇到了一个单独的回车换行,则表示请求头结束 } while (!line.equals("\r\n")); //--输消息的体 System.out.print(readLine(is, contentLength)); //关闭流 is.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /* * 这里咱们本身模拟读取一行,由于若是使用API中的BufferedReader时,它是读取到一个回车换行后 * 才返回,不然若是没有读取,则一直阻塞,直接服务器超时自动关闭为止,若是此时还使用BufferedReader * 来读时,由于读到最后一行时,最后一行后不会有回车换行符,因此就会等待。若是使用服务器发送回来的 * 消息头里的Content-Length来截取消息体,这样就不会阻塞 * * contentLe 参数 若是为0时,表示读头,读时咱们仍是一行一行的返回;若是不为0,表示读消息体, * 时咱们根据消息体的长度来读完消息体后,客户端自动关闭流,这样不用先到服务器超时来关闭。 */ private static String readLine(InputStream is, int contentLe) throws IOException { ArrayList lineByteList = new ArrayList(); byte readByte; int total = 0; if (contentLe != 0) { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); total++; } while (total < contentLe);//消息体读还未读完 } else { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); } while (readByte != 10); } byte[] tmpByteArr = new byte[lineByteList.size()]; for (int i = 0; i < lineByteList.size(); i++) { tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue(); } lineByteList.clear(); return new String(tmpByteArr, encoding); } }
上面都是采用的是io;由于NIO的缘故 这些代码都不是本身写的;后面准备本身写NIO的实现;(就这一点东东就花了了我一天时间 真心伤不起呀;基础 基础 基础夯实真的很重要) 在此记录以备后用