一臺主機有個IP地址(邏輯地址),MAC(物理地址)。用IP可以找到一臺主機。
能交換數據的是進程,進程之間交換數據,不是計算機。
一個程序.exe,靜態的概念,一個進程,在內存中,運行態的概念。
某些進程會占用固定的端口,進程與端口對應。
把一個端口和進程建立聯系的叫做綁定。
FTP《=》端口21
進程間通訊是兩個端口建立連接。
由于機器通訊,要有相同的語言,為保證數據正常交互,預先約定好協議。
網絡體系架構,解決異構性問題采用的是分層方法--把復雜網絡互聯問題劃分為若干較小的,單一的問題。
分層-〉人解決復雜網絡問題的一般思路。
OSI :
對等層不允許直接通訊,嚴格單項依賴,上層依賴下層提供的服務,下層不依賴于上層工作。
對等層是虛擬連接。
網絡層----〉IP協議(尋址)(路由)
傳輸層----〉TCP傳輸控制協議,UDP用戶數據報協議
TCP有很大開銷,三次握手,保證數據可靠傳輸,
UDP用于對實時性要求的應用。他是把大塊數據分成小的數據報,只發數據報,數據報自己負責尋址,所以不一定路徑一樣,順序可能亂。
數據封裝的概念,下一層對上層數據按照自己的格式進行再次封裝,封裝就是在數據前面加上特定的協議頭部信息。數據打包

上層向一層一次,就封裝一次,到另外一層就是反向的,解封一次。
TCP/IP
應用層
傳輸層
網絡層
網絡接口
端口是一種抽象的軟件結構,與協議相關。
TCP:23和UDP:23不相關。
IP+Port就是一個Socket,是一個對象的概念。就好像電話機,電話號碼和分機號
Socket是傳輸層的。網絡編程要注意在哪一個層次編程。
基于TCP,java.net.ServerSocket,服務器進程。構造函數一個端口號
Socket s = ServerSocket.accept(),阻塞方法,可以返回一個與聯入的客戶端Socket對應的Socket。
客戶端:Socket s1 = new Socket("127.0.0.1",6666);
s和s1不同。
獲得數據,s.getInputStream(),s.getOutputStream()
s.close(),關閉socket,會自動關閉流,至少這時流不再可用。
import java.io.*;
import java.net.*;


public class Server
{
public static void main(String[] args) throws Exception

{
ServerSocket ss = new ServerSocket(8000);
Socket s = ss.accept();
PrintWriter out = new PrintWriter(s.getInputStream());
out.println("Server started!");
out.flush();
s.close();
ss.close();
}
}
import java.io.*;
import java.net.*;


public class Client
{
public static void main(String[] args) throws Exception

{
Socket s = new Socket("127.0.0.1",8000);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = in.readline();
System.out.println(str);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readline();
}
}
以上是最簡單的Server和Client。
以下是本人編的多人群聊的聊天室。
import java.io.*;
import java.net.*;
import java.util.*;


public class NewServer
{
private ServerSocket ss;
private int port = 7777;//默認端口
private static int online = 0;//當前服務在線人數
private List threadList;//客戶端連入Server后,啟動過的線程的集合,以便管理,群發
final static PrintWriter sysout;//服務器本地輸出,無用,直接System.out,沒問題。

static
{
sysout = new PrintWriter(System.out,true);
}
public NewServer(int port)

{

if(port!=0)
{//參數為0,采用默認端口
this.port = port;
}

try
{
ss = new ServerSocket(this.port);//綁定
threadList = new ArrayList();
sysout.println("Start service on " + this.port);
while(true)//死循環,用于處理客戶端的連入,并啟動獨立線程,與客戶端交換信息

{
Transmit t = new Transmit(ss.accept());//阻塞住,直到有客戶端連接
threadList.add(t);//將即將啟動的線程,加入list
t.start();
}
}catch(Exception e)

{
e.printStackTrace();
}
}

/** *//**
*
* 私有成員內部類(便于訪問外部類私有屬性),如果改為頂級類沒有問題,封裝了服務器與客戶端交換數據的獨立線程操作。
*/

private class Transmit extends Thread
{
private BufferedReader input;//帶緩沖的字符流,作為輸入流,從中讀取發送到服務器的信息
private PrintWriter output;//帶緩沖的字符流,作為輸出流,輸入字符
private String serverinfo = System.getProperty("os.name")+" "+System.getProperty("os.arch")+" "+System.getProperty("os.version");
private Socket client;//ss.accept()返回的socket
private boolean quit = false;//判斷是否退出

public Transmit(Socket sock)
{
this.client = sock;

try
{
this.input = new BufferedReader(new InputStreamReader(client.getInputStream(),"gb2312"));
this.output = new PrintWriter(client.getOutputStream(),true);//auto flush
output.println("Now,Server has " + (online) + " people online!");
output.println(serverinfo);

}catch(Exception ex)
{}
}

public void run()
{

try
{
while(!quit)

{
String line = input.readLine();
if(line == null) quit = true;

else
{
sysout.println("[ "+new Date().toString()+"Receive word From : "+client.getInetAddress()+" ]: " + line);//本地輸出,可以重定向到文件
if(line.trim().equalsIgnoreCase("EXIT"))

{
output.println("See you");
quit = true;
}
else
sendToOtherMsg(client.getInetAddress().toString(),line);//遍歷threadlist,群發信息
}
}
online--;
}
catch(SocketException e)

{
if(e.getMessage().indexOf("Connection reset")!=-1)//客戶端退出

{
sysout.println(client.getInetAddress() + "offline");
online--;
}
}
catch(Exception e)

{
e.printStackTrace();
}
finally

{

try
{
client.close();//socket會關閉所打開的流,不要強行關閉流,會有問題。

}catch(Exception e)
{}
}
}
//發送信息給其他線程所通訊的客戶端
private void sendToOtherMsg(String ip,String msg)

{
Iterator it = threadList.iterator();
while(it.hasNext())

{
Transmit t = ((Transmit)it.next());
if(!t.isAlive()) //如果線程已經進入死亡狀態,也就是線程已經運行完畢,remove掉

{
it.remove();
continue;
}
t.sendIt("["+ip+"]: "+msg);
}
}
private void sendIt(String msg)

{
output.println(msg);
}
}
public static void main(String[] args)

{
new NewServer(61248);
}
}客戶端:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ChatRoomClient
{
private JTextArea jta;
private JTextField jtf;
private JFrame f;
private Socket conn;
private BufferedReader echo;
private PrintWriter pw;
private boolean done = false;

public ChatRoomClient(String host,int port)
{
creatGUI();

try
{
conn = new Socket();
conn.connect(new InetSocketAddress(host,port),10000);//Socket連接
//通過橋轉換,將socket得到的字節輸入流按照gb2312編碼方式轉換為字符輸入流,再封裝為帶緩沖的過濾流
echo = new BufferedReader(new InputStreamReader(conn.getInputStream(),"gb2312"));
//直接使用PrintWriter這個過濾流封裝字節輸出流為字符流,并帶有緩沖,比BufferedWriter方法更多。
pw = new PrintWriter(conn.getOutputStream(),true);//auto flush
jta.append("Connected to " + conn.getInetAddress() + ":" + conn.getPort() + "\n");

while(!done)
{
String info = echo.readLine();
jta.append(info+"\n");
}
jta.append("client will be closed in 2s.\n");
Thread.sleep(2000);
System.exit(0);
}
catch(SocketException ex)

{
if(ex.getMessage().indexOf("Connection reset")!=-1)//服務器關閉
jta.append("Server down!\n");
if(ex.getMessage().indexOf("Connection refused: connect")!=-1)//服務器不通
jta.append("connection refused!\nplease check network!\n");
}
catch(Exception ex)

{
ex.printStackTrace();
}
finally

{

try
{
conn.close();//只關閉socket
}catch(Exception ex)

{
}
}
}
private void creatGUI()

{
jta=new JTextArea();
jta.setEditable(false);
jtf=new JTextField();
f=new JFrame("Chat Client");
JScrollPane jp=new JScrollPane(jta);//構建帶滑動條的JTextField
f.getContentPane().add(jp);
f.getContentPane().add(jtf,"South");//JDK 1.5取消getContentPane,直接add沒問題
f.setSize(600,400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//右上角的叉子,生效,關閉窗體
f.setVisible(true);//設置可見,否則不可見

jtf.addActionListener(new ActionListener()
{//添加事件處理

public void actionPerformed(ActionEvent e)
{
String s=jtf.getText();
if(s.trim().equalsIgnoreCase("EXIT"))
done = true;//讓主線程的while退出,進而結束Client
pw.println(s);//利用輸出流,輸出到服務器信息。
jtf.setText("");
}
});
}

public static void main(String[] args)
{
ChatRoomClient c=new ChatRoomClient("127.0.0.1",7777);
}
}

UDP編程
編寫一個時間服務器,客戶端就向服務器索取一個時間。
import java.io.*;
import java.net.*;
import java.util.*;


public class Server
{

static byte[] getTime()
{
Date d= new Date();
return d.toString().getBytes();
}
public static void main(String[] args) throws Exception

{
DatagramPacket inDataPacket = null;
DatagramPacket outDataPacket = null;
byte[] msg= new byte[100];
byte[] time;
InetAddress clientAddress;
int clientPort;
DatagramSocket datagramSocket = new DatagramSocket(13);
System.out.println("UDP server active on port 13");

while(true)
{
inDataPacket = new DatagramPacket(msg, msg.length);
// Get the message.
datagramSocket.receive(inDataPacket);
String s=new String(inDataPacket.getData());
System.out.println(s);
//============================================================
// Retrieve return address information, including InetAddress
// and port from the datagram packet just recieved.
clientAddress = inDataPacket.getAddress();
clientPort = inDataPacket.getPort();
// Get the current time.
time = getTime();
//set up a datagram to be sent to the client using the
//current time, the client address and port
outDataPacket = new DatagramPacket(time, time.length, clientAddress, clientPort);
//finally send the packet
datagramSocket.send(outDataPacket);
}
}
}UDP的端口與TCP上的端口沒關系,端口和協議有關。
import java.io.*;
import java.net.*;


public class Client
{
public static void main(String[] args) throws Exception

{
DatagramSocket ds = new DatagramSocket();
String s = "Hello World";
DatagramPacket outDataPacket = new DatagramPacket(s.getBytes(),s.length(),InetAddress.getLocalHost(),13);
ds.send(outDataPacket);
byte[] msg = new byte[100];
String receivedMsg;
DatagramPacket inDataPacket = new DatagramPacket(msg, msg.length);
ds.receive(inDataPacket);
receivedMsg = new String(inDataPacket.getData(), 0, inDataPacket.getLength());
System.out.println(receivedMsg);
//close the socket
ds.close();
}
}服務器需要客戶端先向服務器發送一個信息,服務器才能提供服務。再回復信息,因為UDP面向非連接的。
Socket之間交換數據。
交換DatagramPacket,內容在字節數據中,發送方在Pocket寫上地址和端口,send。
接收方必須準備一個空信,以便接收內容。received,將字節數組裝滿。
=========================================
URL編程
import java.io.*;
import java.net.*;
import java.util.*;


public class URLConnectionTest
{

public static void main(String[] args)
{

try
{
String urlName;
if (args.length > 0) urlName = args[0];
else urlName = "http://www.tarena.com.cn";
//step 1. Create a URL
URL url = new URL(urlName);
URLConnection con = url.openConnection();
//step 2. Connect to the server
con.connect();

// print header fields

int n = 1;
String key;

while ((key = con.getHeaderFieldKey(n)) != null)
{
String value = con.getHeaderField(n);
System.out.println(key + " = " + value);
n++;
}

// print convenience functions
System.out.println();
System.out.println("getContentType: " + con.getContentType());
System.out.println("getContentLength: " + con.getContentLength());
System.out.println("getContentEncoding: " + con.getContentEncoding());
System.out.println("getDate: " + con.getDate());
System.out.println("getExpiration: " + con.getExpiration());
System.out.println("getLastModifed: " + con.getLastModified());
System.out.println();

//step 3 and 4. Get an InputStream and encapsulate it
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));

// print first ten lines of contents
String line;
n = 1;
//step 5. Read info from the stream

while ((line = in.readLine()) != null && n <= 100)
{
System.out.println(line);
n++;
}
if (line != null) System.out.println(". . .");
}

catch (IOException exception)
{
exception.printStackTrace();
}
}
}

posted on 2005-12-29 14:19
北國狼人的BloG 閱讀(377)
評論(1) 編輯 收藏