轉自:http://www.cnblogs.com/oubo/archive/2012/01/16/2394641.html
一、網絡編程基本概念
1.OSI與TCP/IP體系模型
2.IP和端口
解決了文章最開始提到的定位的問題。
IP在互聯網中能唯一標識一台計算機,是每一台計算機的唯一標識(身份證);網絡編程是和遠程計算機的通信,所以必須先能定位到遠程計算機;IP幫助解決此問題;一台計算機中可能有很多進程,具體和哪一個進程進行通信,這就得靠端口來識別;
IP和端口能唯一定位到需要通信的進程。這里的IP表示地址,區別於IP協議。在OSI體系還是TCP/IP體系中,IP協議位於網際層,來封裝IP地址到報文中。
3.TCP和UDP協議
TCP是Tranfer Control Protocol的簡稱,是一種面向連接的保證可靠傳輸的協議。通過TCP協議傳輸,得到的是一個順序的無差錯的數據流。發送方和接收方的成對的兩個socket之間必須建立連接,以便在TCP協議的基礎上進行通信,當一個socket(通常都是server socket)等待建立連接時,另一個socket可以要求進行連接,一旦這兩個socket連接起來,它們就可以進行雙向數據傳輸,雙方都可以進行發送或接收操作。
UDP是User Datagram Protocol的簡稱,是一種無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。
比較:
UDP:
- 每個數據報中都給出了完整的地址信息,因此無需要建立發送方和接收方的連接。
- UDP傳輸數據時是有大小限制的,每個被傳輸的數據報必須限定在64KB之內。
- UDP是一個不可靠的協議,發送方所發送的數據報並不一定以相同的次序到達接收方
TCP:
- 面向連接的協議,在socket之間進行數據傳輸之前必然要建立連接,所以在TCP中需要連接時間。
- TCP傳輸數據大小限制,一旦連接建立起來,雙方的socket就可以按統一的格式傳輸大的數據。
- TCP是一個可靠的協議,它確保接收方完全正確地獲取發送方所發送的全部數據。
數據楨:
應用:
- TCP在網絡通信上有極強的生命力,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數據被可靠地傳輸。但是可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然占用計算機的處理時間和網絡的帶寬,因此TCP傳輸的效率不如UDP高。
- UDP操作簡單,而且僅需要較少的監護,因此通常用於局域網高可靠性的分散系統中client/server應用程序。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些。
4.Socket
Socket是網絡驅動層提供給應用程序編程接口和一種機制。我們可以把 Socket 比喻成是一個港口碼頭。應用程序只要把貨物放到港口碼頭上,就算完成了貨物的運送。對於接收方應用程序也要創建一個港口碼頭,只需要等待貨物到達碼頭后將貨物取走。
Socket 是在應用程序中創建的,它是通過一種綁定機制與驅動程序建立關系,告訴自己所對應的 IP 和 Port。在網絡上傳輸的每一個數據幀,必須包含發送者的 IP 地址和端口號。創建完 Socket 以后,應用程序寫入到 Socket 的數據,由 Socket 交給驅動程序向網絡上發送數據,計算機從網絡上收到與某個 Socket 綁定的 IP 和 Port 相關的數據后,由驅動程序再交給 Socket ,應用程序就可以從這個 Socket 中讀取接收到的數據。網絡應用程序就是這樣通過 Socket 發送和接收的。
Socket數據發送過程:
Socket數據接收過程:
5.常用應用層協議
二、Java網絡編程常用類
1.InteAddress類
Java中的InetAddress是一個代表IP地址的封裝。IP地址可以由字節數組和字符串來分別表示,InetAddress將IP地址以對象的形式進行封裝,可以更方便的操作和獲取其屬性。InetAddress沒有構造方法,可以通過兩個靜態方法獲得它的對象。
//根據主機名來獲取對應的InetAddress實例 InetAddress ip = InetAddress.getByName("www.baidu.com"); //判斷是否可達 System.out.println("baidu是否可達:" + ip.isReachable(2000)); //獲取該InetAddress實例的IP字符串 System.out.println(ip.getHostAddress()); //根據原始IP地址(字節數組形式)來獲取對應的InetAddress實例 InetAddress local = InetAddress.getByAddress(new byte[]{127,0,0,1}); System.out.println("本機是否可達:" + local.isReachable(5000)); //獲取該InetAddress實例對應的全限定域名 System.out.println(local.getCanonicalHostName());
2.URL和URLConnection類
網絡中的URL(Uniform Resource Locator)是統一資源定位符的簡稱。它表示Internet上某一資源的地址。通過URL我們可以訪問Internet上的各種網絡資源,比如最常見的WWW,FTP站點。 URL可以被認為是指向互聯網資源的“指針”,通過URL可以獲得互聯網資源相關信息,包括獲得URL的InputStream對象獲取資源的信息,以及一個到URL所引用遠程對象的連接URLConnection。 URLConnection對象可以向所代表的URL發送請求和讀取URL的資源。通常,創建一個和URL的連接,需要如下幾個步驟:
- 創建URL對象,並通過調用openConnection方法獲得URLConnection對象;
- 設置URLConnection參數和普通請求屬性;
- 向遠程資源發送請求;
- 遠程資源變為可用,程序可以訪問遠程資源的頭字段和通過輸入流來讀取遠程資源返回的信息。
這里需要重點討論一下第三步:如果只是發送GET方式請求,使用connect方法建立和遠程資源的連接即可;如果是需要發送POST方式的請求,則需要獲取URLConnection對象所對應的輸出流來發送請求。這里需要注意的是,由於GET方法的參數傳遞方式是將參數顯式追加在地址后面,那么在構造URL對象時的參數就應當是包含了參數的完整URL地址,而在獲得了URLConnection對象之后,就直接調用connect方法即可發送請求。而POST方法傳遞參數時僅僅需要頁面URL,而參數通過需要通過輸出流來傳遞。另外還需要設置頭字段。以下是兩種方式的代碼:
//1. 向指定URL發送GET方法的請求 String urlName = url + "?" + param; URL realUrl = new URL(urlName); //打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); //設置通用的請求屬性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); //建立實際的連接 conn.connect(); //2. 向指定URL發送POST方法的請求 URL realUrl = new URL(url); //打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); //設置通用的請求屬性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); //發送POST請求必須設置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); //獲取URLConnection對象對應的輸出流 out = new PrintWriter(conn.getOutputStream()); //發送請求參數 out.print(param);
3.URLDecoder和URLEncoder
這兩個類可以別用於將application/x-www-form-urlencoded MIME類型的字符串轉換為普通字符串,將普通字符串轉換為這類特殊型的字符串。使用URLDecoder類的靜態方法decode()用於解碼,URLEncoder類的靜態方法encode()用於編碼。具體使用方法如下:
//將application/x-www-form-urlencoded字符串轉換成普通字符串 String keyWord = URLDecoder.decode("%E6%9D%8E%E5%88%9A+j2ee", "UTF-8"); System.out.println(keyWord); //將普通字符串轉換成 application/x-www-form-urlencoded字符串 String urlStr = URLEncoder.encode( "ROR敏捷開發最佳指南" , "GBK"); System.out.println(urlStr);
4.Socket和ServerSocket類
網絡上的兩個程序通過一個雙向的通訊連接實現數據的交換,這個雙向鏈路的一端稱為一個Socket。Socket通常用來實現客戶方和服務方的連接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個端口號唯一確定。 但是,Socket所支持的協議種類也不光TCP/IP一種,因此兩者之間是沒有必然聯系的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。 Server端Listen(監聽)某個端口是否有連接請求,Client端向Server端發出Connect(連接)請求,Server端向Client端發回Accept(接受)消息。一個連接就建立起來了。Server端和Client端都可以通過Send,Write等方法與對方通信。 TCP Socket的通信過程如下圖:
5.DatagramSocket類
UDP協議是一種不可靠的網絡協議,它在通訊實例的兩端個建立一個Socket,但這兩個Socket之間並沒有虛擬鏈路,這兩個Socket只是發送和接受數據報的對象。 包java.net中提供了兩個類DatagramSocket和DatagramPacket用來支持數據報通信,DatagramSocket用於在程序之間建立傳送數據報的通信連接, DatagramPacket則用來表示一個數據報。 DatagramSocket的構造方法:
DatagramSocket(); DatagramSocket(int prot); DatagramSocket(int port, InetAddress laddr);
其中,port指明socket所使用的端口號,如果未指明端口號,則把socket連接到本地主機上一個可用的端口。laddr指明一個可用的本地地址。給出端口號時要保證不發生端口沖突,否則會生成SocketException類例外。注意:上述的兩個構造方法都聲明拋棄非運行時例外SocketException,程序中必須進行處理,或者捕獲、或者聲明拋棄。 用數據報方式編寫client/server程序時,無論在客戶方還是服務方,首先都要建立一個DatagramSocket對象,用來接收或發送數據報,然后使用DatagramPacket類對象作為傳輸數據的載體。
三、總結
- 網絡編程的核心是IP、端口、協議三大元素
- 網絡編程的本質是進程間通信
- 網絡編程的2個主要問題:1是定位主機,2是數據傳輸
參考資料:
http://blog.csdn.net/driverking/article/details/6573992 http://blog.sina.com.cn/s/blog_6213b4e50100je4g.html http://52android.blog.51cto.com/2554429/482954 http://hi.baidu.com/refresh/blog/item/1ab994dd4f6957315982ddaa.html
/////////////////////////////////////////////////////////////////////
String url = "http://www.xxxxxx.com";
String params = "clid="+clid_str+"&trid="+clnt.getTrid()+"&checksum="+clnt.getChecksum()+
"&domainname="+clnt.getDomainname()+"&period="+period+"&ns1="+clnt.getNs1()+"&ns2="+clnt.getNs2()+
"®_company="+reg_company+"®_name="+reg_name+"®_email="+clnt.getReg_email()+"®_addr="+
reg_addr+"®_postcode="+clnt.getReg_postcode()+"®_city="+clnt.getReg_city()+"®_province="
+clnt.getReg_province()+"®_country="+clnt.getReg_country()+"®_phone="+clnt.getReg_phone()+"®_fax="+clnt.getReg_fax()
+"&adm_company="+adm_company+"&adm_name="+adm_name+"&adm_email="+clnt.getAdm_email()+"&adm_addr="+adm_addr+"&adm_postcode="+clnt.getAdm_postcode()
+"&adm_city="+clnt.getAdm_city()+"&adm_province="+clnt.getAdm_province()+"&adm_country="+clnt.getAdm_country()+"&adm_phone="+clnt.getAdm_phone()+"&adm_fax="+clnt.getAdm_fax()+"&password="+clnt.getPassword();
//////////////////////////////////////////////////////////////////
import java.sql.Connection; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List;
import org.evision.common.DBConnection;
import checkOnTime.AddDbAndAddUser; import connect.MySqlConnect; import dao.DealDao; import dao.DomDao; import dao.QuoinfoDao; import dao.QuotaDao; import dao.UserDbDao; import email.sendEmail; import entity.Dom; import entity.Quoinfo; import entity.RegDomain; import entity.User; import evisionAPI.CheckSum; import evisionAPI.EvisionAPI;
public class Receive { private static String sql = ""; private static DBConnection dbconn; private static sendEmail sdEmail; private String message;
public void execute(String[] orderID,String orderId,String description,String price,User user) { sendEmail send = new sendEmail(); sdEmail = new sendEmail(); dbconn = new DBConnection(); // CheckSum chksm = new CheckSum(); EvisionAPI api = new EvisionAPI(); DomDao dmdao = new DomDao(); DealDao dDao = new DealDao(); FTPClass fclass = new FTPClass(); QuotaDao qtDao = new QuotaDao(); Quoinfo account = new Quoinfo(); int count = 0; // String pwd = ""; sql = "insert into deallist values(null,'"+orderId+"','"+user.getUser_id()+"','"+description+"','"+getNow()+"','"+price+"')"; //insert the value of deal's detail into deal list dbconn.doExecute(sql); for(int i = 0;i < orderID.length;i++){ sql = "update `order` set orderStatus='checked' where orderID="+Integer.parseInt(orderID[i])+""; // sendEmail send = new sendEmail(); if(dmdao.getRegDomain(Integer.parseInt(orderID[i]), user.getUser_id()) != null) { RegDomain temp = new RegDomain(); temp = dmdao.getRegDomain(Integer.parseInt(orderID[i]), user.getUser_id()); temp.setAdm_email(user.getUser_email()); temp.setReg_email(user.getUser_email()); temp.setChecksum(CheckSum.Checksum(7837622, temp.getTrid(), "Wuhaosdwh0213059")); temp.setReg_time(getNow()); //TODO這邊要添加更新域名注冊時間的信息 if(api.register(temp))/////////////////////////////////////////// { String title = "濟南新視界網絡科技-域名注冊提示"; String content = "尊敬的新視界用戶" +user.getUser_name() +",您好!您在新視界網絡科技注冊的域名" +temp.getDomainname() +"已注冊成功!\n" +"相應的域名管理密碼為" +temp.getPassword() +",請登錄網址http://mgt.dnsoray.com/對網站信息進行維護!謝謝您的支持!"; send.send(user.getUser_email(), title, content); // sdEmail.send(user.getUser_email(), "濟南新視界網絡科技-域名注冊提示", "尊敬的新視界用戶"+user.getUser_name()+",您好!您在新視界網絡科技注冊的域名"+temp.getDomainname()+"已注冊成功!\n"+ // "相應的域名管理密碼為"+temp.getPassword()+",請登錄網址http://mgt.dnsoray.com/對網站信息進行維護!謝謝您的支持!"); } } else if(dDao.getOrder(Integer.parseInt(orderID[i])).getProductType().equals("quota")) { account = fclass.FTPOpen(Integer.parseInt(orderID[i])); int dbYear=account.getPeriod();//quoinfo.period(year); int dbsize = 20480; String user_name = user.getUser_name(); Connection mysqlcon=MySqlConnect.getConnect(); String[] stringArray= new AddDbAndAddUser().createDbAndDbUser(user_name);//返回新生成的數據庫名字和密碼 String dbName = stringArray[0]; String dbPass = stringArray[1]; UserDbDao userDbDao=new UserDbDao(); userDbDao.makeRecordAddUser(stringArray[0], dbsize, account.getFtpname(), dbYear, mysqlcon); MySqlConnect.closeConnect(mysqlcon); String ftptype = null; if(account.getFtptype() == 1){ ftptype = "JSP"; } else if(account.getFtptype() == 2){ ftptype = "PHP"; } else if(account.getFtptype() == 3){ ftptype = "ASP"; } String title = "新視界網絡科技"+ftptype+"類型的域名空間開通通知-no reply"; QuoinfoDao qDao= new QuoinfoDao(); int period = qDao.getPeriod(Integer.parseInt(orderID[i])); int prodecutid = qDao.getProdecutid(Integer.parseInt(orderID[i])); String expiration = qDao.getQuotaexpiration(prodecutid); String time = ""; if("".equals(expiration)){ time="個月"; }else if(period == 7 && !"".equals(expiration)){ time = "天"; }else{ time = "年"; } String subject = "您好!濟南新視界網絡科技感謝您的支持!您在新視界賬戶名為" + user_name + "的用戶,已開通" + ftptype + "類型的域名空間,有效期為"+account.getPeriod()+time+"。\n" + "\n您上傳網站的FTP用戶名為 " + account.getFtpname() + "\n對應的密碼為" + account.getFtppass() + "\n數據庫用戶名為" + dbName + "\n數據庫密碼為" + dbPass + "\n請您登錄phpadmin.jnevision.net進行數據庫操作\n" + "FTP上傳網站的IP地址是58.56.17.148,連接數據庫的地址為phpadmin.jnevision.net,另外請到以下地址點擊進入虛擬空間管理,綁定您的域名http://www.jnevision.net/user/manager.jsp\n新視界網絡現為您提供一個免費域名:free"+ftptype+".jnevision.net/"+user_name+"\n以上信息是您試用新視界空間服務的憑證,請牢記並妥善保存\n\n|||||||||||||||||||||||||||||\n" + "\n此郵件由系統發出,請勿直接回復!再次感謝您的支持!"; sdEmail.send(user.getUser_email(), title, subject); } // dbconn.doExecute(sql); }//reset the 'orderStatus' of the table `order` }
private static String getNow(){ SimpleDateFormat dFormat = new SimpleDateFormat("yyyyMMdd"); String now = dFormat.format(new Date()); return now; }
public static void main(String[] args) { String[] orderID = {"123","1234","12345"}; EvisionAPI api = new EvisionAPI(); DomDao dmdao = new DomDao(); User user = new User(); user.setUser_email("alba_2@163.com"); user.setUser_name("sb"); user.setUser_id(11); for(int i = 0;i < orderID.length;i++){ if(dmdao.getRegDomain(Integer.parseInt(orderID[i]), user.getUser_id()) != null) { RegDomain temp = new RegDomain(); temp = dmdao.getRegDomain(Integer.parseInt(orderID[i]), user.getUser_id()); temp.setChecksum(CheckSum.Checksum(7837622, temp.getTrid(), "Wuhaosdwuhao830215")); if(!api.register(temp)) { String title = "1";//濟南新視界網絡科技 域名注冊提示 String content = "尊敬的新視界用戶"+user.getUser_name()+",您好!您在新視界網絡科技注冊的域名"+temp.getDomainname()+"已注冊成功!\n"+ "相應的域名管理密碼為"+temp.getPassword()+",請登錄網址http://mgt.dnsoray.com/對網站信息進行維護!謝謝您的支持!"; sendEmail send = new sendEmail(); send.send(user.getUser_email(), title, content); System.out.println(content); } }
} }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; } }