随笔-159  评论-114  文章-7  trackbacks-0

一台主机有个IP地址(逻辑地址),MAC(物理地址)。用IP可以找到一台主机。

能交换数据的是进程,进程之间交换数据,不是计算机。

一个程序.exe,静态的概念,一个进程,在内存中,运行态的概念。

某些进程会占用固定的端口,进程与端口对应。

把一个端口和进程建立联系的叫做绑定。

FTP《=》端口21

进程间通讯是两个端口建立连接。

由于机器通讯,要有相同的语言,为保证数据正常交互,预先约定好协议。

网络体系架构,解决异构性问题采用的是分层方法--把复杂网络互联问题划分为若干较小的,单一的问题。

分层-〉人解决复杂网络问题的一般思路。

OSI :

对等层不允许直接通讯,严格单项依赖,上层依赖下层提供的服务,下层不依赖于上层工作。

对等层是虚拟连接。

网络层----〉IP协议(寻址)(路由)

传输层----〉TCP传输控制协议,UDP用户数据报协议

TCP有很大开销,三次握手,保证数据可靠传输,

UDP用于对实时性要求的应用。他是把大块数据分成小的数据报,只发数据报,数据报自己负责寻址,所以不一定路径一样,顺序可能乱。



数据封装的概念,下一层对上层数据按照自己的格式进行再次封装,封装就是在数据前面加上特定的协议头部信息。数据打包

Untitled-1.jpg


上层向一层一次,就封装一次,到另外一层就是反向的,解封一次。

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 阅读(376) 评论(1)  编辑  收藏

评论:
# re: Java网络编程 2006-07-02 10:56 | Sophia
GG,谢谢哦,你的源程序救了我一命啊!!!!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: