網絡編程技術是互聯網技術中的主流編程技術之一,懂的一些基本的操做是很是必要的。這章主要講解網絡編程,UDP和Socket編程,以及使用Socket作一個簡單的聊天軟件。html
所有代碼下載:連接java
網絡編程實質實質就是兩個(或多個)設備(例如計算機)之間的數據傳輸。而要實現兩臺計算機經過互聯網鏈接進行數據傳輸,必輸要知足計算機網絡的5層協議(物理層,數據鏈路層,網絡層,運輸層,應用層);固然有劃分可能不一樣,但如今你們比較容易接受理解的是五層模型。而其中前三層物理層,數據鏈路層以及網絡層,做爲java程序員暫時是不能直接對他進行控制的。而本章講的網絡編程是處在運輸層和應用層中。對與計算機網絡,能夠參看個人博客互聯網協議入門程序員
URL基本格式: protocol://hostname:port/resourcename#anchor protocol:使用的協議,能夠是http,ftp,news,telnet等 hostname:主機名 port:端口號,可選 resourcename:資源名,主機上能訪問到的目錄或文件 anchor:標記,可選,指定文件中的有特定標記的位置 如: http://localhost:8080/HttpSer/index.html。
下面主要經過UDP和socket編程來說解網絡編程;編程
DatagramSocket ds = null; //定義一個UDP來發送數據 ds = new DatagramSocket(); //假設發送的數據是個字符串 String hello = "hello world"; //定義一個UDP的數據發送包來發送數據,inetSocketAddress表示要接收的地址 DatagramPacket dp = new DatagramPacket(hello.getBytes() ,hello.getBytes().length,new InetSocketAddress("127.0.0.1", 9999)); for(int i=0;i<10;i++) { //數據發送 ds.send(dp); //線程睡眠1s Thread.sleep(1000); }
服務端:服務器
DatagramSocket ds = null; //UDP接受端鏈接 ds = new DatagramSocket(9999); //定義將UDP的數據包接收到什麼地方 byte[] buf = new byte[1024]; //定義UDP的數據接收包 DatagramPacket dp = new DatagramPacket(buf, buf.length); while(true) { //接收數據包 ds.receive(dp); //將數據轉換輸出: String str = new String(dp.getData(),0,dp.getLength()); System.out.println(str); }
//進行監聽,當客戶端沒數據發送過來時,停在這裏; Socket s=serverSocket.accept();
2.通訊類:Socket
服務器端和客戶端能夠經過Socket類進行通訊:
客戶端創建socket類過程:網絡
//創建socket客戶端:第一個參數:ip地址;第二個參數:發送的端口,假如沒有服務器,會停在這裏,而後扔出異常; Socket socket=new Socket("192.168.1.105", 8888);
經過socket類能夠得到輸入輸出流進行通訊:socket
//得到socket的輸出流 PrintWriter out=new PrintWriter(socket.getOutputStream()); //得到socket的輸入流 BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
public static void main(String[] args) { Socket socket=null; PrintWriter out=null; BufferedReader in=null; try { //創建socket客戶端:第一個參數:ip地址;第二個參數:發送的端口,假如沒有服務器,會停在這裏,而後扔出異常; socket=new Socket("192.168.1.105", 8888); //得到本機分配的當地socket端口 System.out.println("當地端口:"+socket.getLocalPort()); //得到本機分配的當地socket端口 System.out.println("遠程端口:"+socket.getPort()); //得到socketAddress System.out.println("遠程adress:"+socket.getRemoteSocketAddress()); System.out.println("本地adress:"+socket.getLocalSocketAddress()); //得到inetAddress System.out.println("遠程inetAddress:"+socket.getInetAddress()); System.out.println("本地inetAddress:"+socket.getLocalAddress()); //得到socket的輸出流 out=new PrintWriter(socket.getOutputStream()); //得到socket的輸入流 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); //發送數據 out.println("peace"); //刷新纔會當即發送 out.flush(); //接收數據 String str=null; //此去會一直等待服務端發送一個數據; str=in.readLine(); System.out.println("收到:"+str); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //關閉鏈接 if(socket!=null){ try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
服務端:ide
public static void main(String[] args) { ServerSocket serverSocket=null; PrintWriter out=null; BufferedReader in=null; Socket s=null; int i=0; try { //服務器的建立:建立相應的serversocket serverSocket=new ServerSocket(8888); while(true){ try { //進行監聽,當客戶端沒數據發送過來時,停在這裏; s=serverSocket.accept(); //得到本機分配的當地socket端口 System.out.println("當地端口:"+s.getLocalPort()); //得到本機分配的當地socket端口 System.out.println("遠程端口:"+s.getPort()); //得到socketAddress System.out.println("遠程adress:"+s.getRemoteSocketAddress()); System.out.println("本地adress:"+s.getLocalSocketAddress()); //得到inetAddress System.out.println("遠程inetAddress:"+s.getInetAddress()); System.out.println("本地inetAddress:"+s.getLocalAddress()); //得到socket的輸出流,關閉socket時,會自動關閉socket的輸出輸入留 out=new PrintWriter(new OutputStreamWriter(s.getOutputStream())); //得到socket的輸出流,關閉socket時,會自動關閉socket的輸出輸入留 in=new BufferedReader(new InputStreamReader(s.getInputStream())); //將客戶端發過來的數據輸出: String str=null; str=in.readLine(); System.out.println("收到"+str); out.println("hello"+i++); out.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(s!=null){ s.close(); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(serverSocket!=null){ try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
該聊天進程能夠實現指定好友聊天,和羣聊。只是簡單的演示。函數
package com.rlovep.clinet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; /** * * @ClassName: TalkClinet * @Description: 聊天客戶端: * @author peace w_peace@163.com * @date 15 Oct 2015 7:21:22 pm * */ public class TalkClinet { // 得到控制檯輸入 private BufferedReader sysin = null; // socket private Socket s = null; private BufferedReader in = null; private PrintWriter out = null; // 線程中止flag private boolean flag = true; //單聊標誌 private final static String single="single"; public static void main(String[] args) { // 啓動客戶端: new TalkClinet().start(); } /** * * @Title: start * @Description: 主要做用:啓動發送和接收任務 * @return:void * @throws * @author peace w_peace@163.com */ public void start(){ try { // 得到系統輸入: sysin = new BufferedReader(new InputStreamReader(System.in, "utf-8")); // 設置名字: System.out.println("請輸入用戶名:"); String name = sysin.readLine(); // 創建客戶端socket s = new Socket("127.0.0.1", 8888); // 得到socket輸出out out = new PrintWriter(s.getOutputStream(), true); out.println(name); // 得到socket輸入 in in = new BufferedReader(new InputStreamReader(s.getInputStream())); // 創建接收線程;緣由獲取系統輸入會阻塞主線程 new Thread(new ClinetThread()).start(); // 發送消息: String str = null; while (flag && ((str = sysin.readLine()) != null)) { //判斷是否爲單聊標誌。若是不是單聊,就羣發消息 if(single.equalsIgnoreCase(str)){ System.out.println("請輸入想跟誰聊 :"); //獲取系統輸入: if(flag && ((str = sysin.readLine()) != null)) { //發送單聊標誌 out.println(single) ; } } //向服務端發送內容: out.println(str); } } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ //關閉資源 if(sysin!=null){ try { sysin.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(s!=null){ try { s.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } private class ClinetThread implements Runnable{ /** * * @Title: recive * @Description: 接收消息,當消息爲disconnect時退出,此去須要在按下一次回車用來終止系統輸入; * @return:void * @throws * @author peace w_peace@163.com */ private void recive(){ try { //接收服務端消息 String str=in.readLine(); if(str!=null){ //若是是結束聊天,就退出線程 if("disconnect".equals(str)){ stop(); System.out.println("回車退出:"); } else { //不然顯示消息 System.out.println(str); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //線程中止方法 public void stop() { flag=false; } //線程主要任務 @Override public void run() { while(flag){ //接收消息函數調用 recive(); } } } }
4.服務端代碼以下:ui
package com.rlovep.server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.HashMap; import java.util.Map; public class TalkServer { //保存聊天線程: private Map<String, ServerThread> map = new HashMap<String, ServerThread>(); public static void main(String[] args) { //啓動服務器 new TalkServer().start(); } /** * * @Title: start * @Description: 爲每個客戶端建立一個獨立線程 * @return:void * @throws * @author peace w_peace@163.com */ public void start(){ //服務器servesocket ServerSocket serverSocket=null; //服務器socket Socket socket=null; try { //服務器建立 serverSocket=new ServerSocket(8888); //死循環,用於接收更多的客戶端 while(true){ //聊天線程建立 socket=serverSocket.accept(); //爲每個客戶端創建一個服務線程。 ServerThread st=new ServerThread(socket); new Thread(st).start(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ //釋放資源 try { if(serverSocket!=null){ serverSocket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * * @ClassName: ServerThread * @Description: 聊天線程 * @author peace w_peace@163.com * @date 15 Oct 2015 8:31:44 pm * */ private class ServerThread implements Runnable{ //相應的socket private Socket socket=null; private BufferedReader in=null; private PrintWriter out=null; //每一個聊天的名字 private String name=null; //聊天頭 private String meshead=null; //中止線程標誌位 private boolean flag=true; //單聊標誌位: private boolean sin=false; /** * * <p>Title:線程構造器 </p> * <p>Description:用來建立線程,以及初始化,和將線程加入map </p> * @param socket * @throws IOException */ public ServerThread(Socket socket) throws IOException { //得到socket this.socket=socket; //得到輸出和輸入 out=new PrintWriter(socket.getOutputStream(),true); //得到用戶名字 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); name=in.readLine(); System.out.println(name+"上線了"); //製做聊天頭 meshead=name+"["+socket.getInetAddress().getHostAddress()+":"+socket.getPort()+"]"; //將線程加入map:key爲名字;value爲線程 map.put(name, this); //提醒全部用戶 send(meshead+"上線了"); } /** * * @Title: send * @Description: 發送消息(羣發) * @param msg * @return:void * @throws * @author peace w_peace@163.com */ public void send(String msg){ //迭代羣發 for(ServerThread thread:map.values()){ thread.out.println(msg); } } /** * * @Title: Receiver * @Description: 接收消息,並轉發 * @throws IOException * @return:void * @author peace w_peace@163.com */ public void Receiver() throws IOException{ String str=null; ServerThread qq=null; //接收消息 while((str=in.readLine())!=null){ //若是消息爲quit則退出 if("quit".equalsIgnoreCase(str)){ stop(); //給客戶端發送關閉連接命令 out.println("disconnect"); break; } //判斷是否爲單聊 if(sin==false) { if(str.equals("single")){ //若是爲單聊就得到想要跟誰聊 if((str=in.readLine())!=null){ //得到另一個客戶端線程 qq=map.get(str); if(qq!=null) sin=true; } } else { //轉發消息 羣發 send(meshead+str); } } //若是是單聊就給對應的客戶端發送消息; else{ //若是爲q則退出單聊 if(str.equals("q")){ sin=false; qq.out.println(name+"對話結束"); } //不然發送消息 else qq.out.println(name+"對你說:"+str); } } } /** * * @Title: stop * @Description: 中止函數 * @return:void * @throws * @author peace w_peace@163.com */ public void stop(){ flag=false; //下線移去碼map; map.remove(name); send(meshead+"已經下線了"); } /** * run方法 */ @Override public void run() { try { while(flag){ //不停接收消息 Receiver(); } } catch(SocketException e){ stop();//客戶端直接關閉引起的錯誤; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ //釋放資源 try { if(socket!=null){ socket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
來自一條小鯊魚wpeace(rlovep.com)