`
fehly
  • 浏览: 248419 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

网络编程

    博客分类:
  • java
阅读更多

计算机网络基础

什么是计算机网络

把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大,功能强的网络系统,从而使众多的计算机可以方便的相互传递信息,共享硬件,软件,数据信息等资源.

计算机网络的主要功能

资源共享

信息传输与集中处理

均衡负荷与分布处理

综合信息服务

计算机网络分类

按规模大小和延伸范围划分:

局域网(LAN-local area network)

城域网(MAN-metropolitan area network)

广域网(WAN-wide area network)

按照网络的拓扑(Topology)结构划分:

环形网,星形网,总线型网等

按照通信,传输的介质来划分:

双绞线网,同轴电缆网,光纤网,卫星网等.

按照信号频带占方式划分:

基带网和宽带网

计算机网络工作模式

专用服务器结构(Server-Based)

又称为"工作站/文件服务器"结构,由若干台微机工作站与一台或多台文件服务器通过通信线路连接起来组成工作站存取服务器文件,共享存储设备.

客户机/服务器模式(Client/Server,C/S)

其中一台或几台较大的计算机集中进行共享数据库的管理和存取,称为服务器,而将其它的应用处理工作分散到网络中其他微机上去做,构成分布式的处理系统.

对等式网络(Peer-to-Peer,P2P)

在拓扑结构上与专用Server与C/S相同,在对等式网络结构中,没有专用服务器,每一个工作站既可以起客户机作用也可以做1服务器作用.

网络通信协议及接口

什么事网络通信协议

计算机网络中实现通信必须有一些约定即通信协议,对速率,传输代码,代码结构,传输控制步骤,出错控制等制定标准.

网络通信接口

为了使两个结点之间能进行对话,必须在它们之间建立通信工具(即接口),使彼此之间,能进行信息交换,接口包括两部分:

硬件装置:实现结点之间的信息传送

软件装置:规定双方进行通信的约定协议

通信协议分层的思想

为什么要分层

由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来,最常用的复合方式是层次方式,即同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系.

通信协议的分层规定

把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准.

数据的封装与拆封

封装:发送方数据在网络模型的各层传送过程中加入头尾的过程

拆封:接受方收到书记后去除相应的头尾的过程.

常用网络通信协议

TCP/IP协议

TCP(Transmission Control Protocol,传输控制协议)

IP(Internet Protocol,网际协议)

HTTP协议

HTTP(Hypertext Transfeer Protocol,超文本传输协议)

FTP协议

FTP(File Transfer Protocol,文本传输协议)

SMTP协议

SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)

POP3/IMAP协议

pop3(Post office Protoco-version3,邮局协议版本3)

IMAP(Internet Message Access Protocol,Internet消息访问协议)

IP地址/域名/端口

IP地址

Tcp/ip使用ip地址来标识源地址和目的地地址

ip地址格式:192.111.12.43

目前正在普遍使用的ip协议时第4版(Version 4)的称为IPv4,新版本(IPV6)协议已开始推广.

域名(Domain Address)

便于记忆的,字符串形式,如:baidu.com

与ip地址间存在映射关系,由位于网络中的域名服务器(DNS,Domain Name Server)负责将域名解析为相应的ip地址.

端口(Port)

逻辑协议上的数据传输通道,或者说模拟通道,Tcp/ip协议约定,每台计算机拥有65536个这种逻辑通信端口.

端口号:用于标识这些端口的整数编号,其取值范围为0-65535

相关API

JDK的java.net包中定义了与ip地址/域名有关的类

java.net.InetAddress

32位或128位无符号数字表示的ip地址

java.net.Inet4Address

继承了InetAddress类,以32位无符号数字表示的IPv4地址,其典型表示形式是由圆点分隔开的4段,取值范围0-255的十进制数值

java.net.Inet6Address

继承了InetAddress,以128位无符号数字表示的ipv6地址,其典型表示形式是由冒号分隔开的8段,取值范围0000-ffff的十六进制数值,例如"1090:2:2:2:1:311:123C:123A"

 

import java.net.InetAddress;

public class TestInetAddress {
	public static void main( String args[]) {
		try{
			InetAddress ia = InetAddress.getLocalHost();
			showInfo(ia);
			
			ia = InetAddress.getByName("www.sina.com.cn");
			showInfo(ia);
		}catch(java.net.UnknownHostException e){
			e.printStackTrace();
		}
		
	}
	
	public static void showInfo(InetAddress ia){
		String name = ia.getHostName();
		String address = ia.getHostAddress();
		System.out.println(name);
		System.out.println(address);
		System.out.println("----------------");
	}
}

URL

URL(Uniform Resource Locator统一资源定位器)用于表示Internet上资源的地址。

URL格式:

<协议名><资源所在主机名>[:<端口号>]<资源名>

例如:http://www.baidu.com/map/index.htm

java.net包定义了对应的URL类常用方法:

public URL(String spec);

public final InputStream openStream() throws IOException

使用URL读取网络资源

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
public class URLReader{
	public static void main(String args[]){
		//System.setProperty("http.proxyHost","192.168.1.1");
		//System.setProperty("http.proxyPort","11080");
		try{
			URL tirc = new URL("http://www.google.cn/");
			BufferedReader in = new BufferedReader(new 
				InputStreamReader(tirc.openStream()));
			String s;
			while((s = in.readLine())!=null)
				System.out.println(s);
			in.close();	
		}catch(MalformedURLException e) {
			System.out.println(e);	
		}catch(IOException e){
			System.out.println(e);
		}	
    }
}

Socket编程

  • 两个进程间可以通过一个双向的网络通信连接实现数据交换,这种通信链路的端点被称为"套接字"(Socket)
  • Socket通常用来实现Client-Server连接.
  • 建立连接时所需的寻址信息:1远程计算机的机器名或ip地址;2试图连接的端口号(Port number)

java.net包中定义了两个类Socket和ServerSocket,分别用来实现双向连接的client和server端.

Socket通信模型

Socket编程基本步骤

  1. 建立网络连接
  2. 打开连接到Socket的输入/输出流;
  3. 通过已打开的i/o流进行数据读/写操作;
  4. 关闭已打开的i/o流和Socket

图像用户界面自由聊天程序

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class TestServer {
	private ServerSocket ss;
	private Socket s;
	private DataInputStream dis;
	private DataOutputStream dos;
	private TextArea ta;
	private TextField tf;
		
	public static void main(String args[]) {
		TestServer ts = new TestServer();
		ts.createUI();
		ts.connect();	
		ts.createThread();
	}
	public void connect(){
		try {		
			ss = new ServerSocket(8888);
			s = ss.accept();
			dis = new DataInputStream(s.getInputStream());
			dos = new DataOutputStream(s.getOutputStream());
		}catch (IOException e) {
			e.printStackTrace();	
			//13701303436  
				
		}
	}
	
	public void createUI(){
		Frame f = new Frame("Server");
		ta = new TextArea();
		tf = new TextField();
		Button send = new Button("发送");
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(tf,"Center");
		p.add(send,"East");
		f.add(ta,"Center");
		f.add(p,"South");
		MyServerListener listener = new MyServerListener(this);
		send.addActionListener(listener);		
		tf.addActionListener(listener);
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);	
			}	
		});
		f.setSize(400,400);
		f.setVisible(true);	
	}

	public void createThread(){
		MyServerReader reader = new MyServerReader(this);
		reader.start(); 
	}
	
	public void close(){
		try{
			dis.close();
			dos.close();
			s.close();
			ss.close();	
		}catch (IOException e) {
			e.printStackTrace();		
		}
	}

	public DataInputStream getDataInputStream(){
		return dis;	
	}
	public DataOutputStream getDataOutputStream(){
		return dos;	
	}
	public TextArea getTextArea(){
		return ta;	
	}
	public TextField getTextField(){
		return tf;	
	}
}

class MyServerListener implements ActionListener{
	private TestServer server;	
	public MyServerListener(TestServer server){
		this.server = server;
	}
	public void actionPerformed(ActionEvent e){
		TextField tf = server.getTextField();
		String info = tf.getText();
		server.getTextArea().append("自己说: " + info + "\n");
		try{
			server.getDataOutputStream().writeUTF(info);	
		}catch (IOException e1) {
			e1.printStackTrace();		
		}
		if(info.equals("bye")){
			server.close();
			System.exit(0);	
		}
		tf.setText("");
		tf.requestFocus();
	}	
}

class MyServerReader extends Thread{
	private TestServer server;
	public MyServerReader(TestServer server){
		this.server = server;	
	}
	public void run(){
		String info;
		DataInputStream dis = server.getDataInputStream();
		TextArea ta = server.getTextArea();
		try{
			while(true){
				info = dis.readUTF();
				ta.append("对方说: " + info + "\n");
				if(info.equals("bye")){
					server.close();
					System.exit(0);
				}
			}		
		}catch (IOException e) {
			e.printStackTrace();		
		}	
	} 	
}

 

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class TestClient {
	private Socket s;
	private DataInputStream dis;
	private DataOutputStream dos;
	private TextArea ta;
	private TextField tf;
		
	public static void main(String args[]) {
		TestClient tc = new TestClient();
		tc.createUI();
		tc.connect();	
		tc.createThread();
	}
	public void connect(){
		try {		
			s = new Socket("127.0.0.1",8888);
			dos = new DataOutputStream(s.getOutputStream());
			dis = new DataInputStream(s.getInputStream());
		}catch (IOException e) {
			e.printStackTrace();		
		}
	}
	
	public void createUI(){
		Frame f = new Frame("Client");
		ta = new TextArea();
		tf = new TextField();
		Button send = new Button("发送");
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(tf,"Center");
		p.add(send,"East");
		f.add(ta,"Center");
		f.add(p,"South");
		MyClientListener listener = new MyClientListener(this);
		send.addActionListener(listener);
		tf.addActionListener(listener);
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);	
			}	
		});
		f.setSize(400,400);
		f.setLocation(600,0);
		f.setVisible(true);	
	}
	
	public void createThread(){
		MyClientReader reader = new MyClientReader(this);
		reader.start(); 
	}
	
	public void close(){
		try{
			dis.close();
			dos.close();
			s.close();
		}catch (IOException e) {
			e.printStackTrace();		
		}
	}

	public DataInputStream getDataInputStream(){
		return dis;	
	}
	public DataOutputStream getDataOutputStream(){
		return dos;	
	}
	public TextArea getTextArea(){
		return ta;	
	}
	public TextField getTextField(){
		return tf;	
	}
}

class MyClientListener implements ActionListener{
	
	private TestClient client;	
	public MyClientListener(TestClient client){
		this.client = client;
	}
	public void actionPerformed(ActionEvent e){
		TextField tf = client.getTextField();
		String info = tf.getText();
		client.getTextArea().append("自己说: " + info + "\n");
		try{
			client.getDataOutputStream().writeUTF(info);	
		}catch (IOException e1) {
			e1.printStackTrace();		
		}
		if(info.equals("bye")){
			client.close();
			System.exit(0);	
		}
		tf.setText("");
		tf.requestFocus();		
	}	
}

class MyClientReader extends Thread{
	private TestClient client;
	public MyClientReader(TestClient client){
		this.client = client;	
	}
	public void run(){
		String info;
		DataInputStream dis = client.getDataInputStream();
		TextArea ta = client.getTextArea();
		try{
			while(true){
				info = dis.readUTF();
				ta.append("对方说: " + info + "\n");
				if(info.equals("bye")){
					client.close();
					System.exit(0);
				}
			}		
		}catch (IOException e) {
			e.printStackTrace();		
		}	
	} 	
}

多用户聊天室程序

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class ChatClient {
	private String name;
	private Socket s;
	private DataInputStream dis;
	private DataOutputStream dos;
	private Frame f;
	private TextArea ta;
	private TextField tf;
	private boolean runnable = true;	
		
	public static void main(String args[]) {
		ChatClient cc = new ChatClient();
		cc.createUI();
		cc.inputName();		
		cc.connect();	
		cc.createThread();
	}
	public void createUI(){
		f = new Frame("Client");
		ta = new TextArea();
		ta.setEditable(false);
		tf = new TextField();
		Button send = new Button("Send");
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(tf,"Center");
		p.add(send,"East");
		f.add(ta,"Center");
		f.add(p,"South");
		MyClientListener listener = new MyClientListener(this);
		send.addActionListener(listener);
		tf.addActionListener(listener);
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				ChatClient.this.shutDown();	
			}	
		});
		f.setSize(400,400);
		f.setLocation(600,0);
		f.setVisible(true);	
		tf.requestFocus();
	}
	public void inputName(){
		String name = javax.swing.JOptionPane.showInputDialog("Input Your Name:");
		this.setName(name);	
		f.setTitle(name);
	}
	public void connect(){
		try {		
			s = new Socket("127.0.0.1",9999);
			dos = new DataOutputStream(s.getOutputStream());
			dis = new DataInputStream(s.getInputStream());
			dos.writeUTF(name);
		}catch (IOException e) {
			e.printStackTrace();		
		}
	}	
	public void createThread(){
		MyClientReader reader = new MyClientReader(this);
		reader.start(); 
	}
	public void stop(){
		runnable = false;	
	}
	public void shutDown(){
		try{
			dos.writeUTF("bye");
			ta.append("Exit in 5 seconds!");
			this.stop();			
			Thread.sleep(5000);
			dis.close();
			dos.close();
			s.close();
		}catch(Exception e){
		}
		System.exit(0);						
	}
	public boolean getRunnable(){
		return runnable;
	}			
	public void setName(String name){
		this.name = name;
	}
	public DataInputStream getDataInputStream(){
		return dis;	
	}
	public DataOutputStream getDataOutputStream(){
		return dos;	
	}
	public TextArea getTextArea(){
		return ta;	
	}
	public TextField getTextField(){
		return tf;	
	}
}

class MyClientListener implements ActionListener{
	
	private ChatClient client;	
	public MyClientListener(ChatClient client){
		this.client = client;
	}
	public void actionPerformed(ActionEvent e){
		TextField tf = client.getTextField();
		String info = tf.getText();
		try{
			client.getDataOutputStream().writeUTF(info);	
		}catch (IOException e1) {
			e1.printStackTrace();		
		}
		if(info.equals("bye")){
			client.shutDown();	
		}
		tf.setText("");
		tf.requestFocus();		
	}	
}

class MyClientReader extends Thread{
	private ChatClient client;
	public MyClientReader(ChatClient client){
		this.client = client;	
	}
	public void run(){
		String info;
		DataInputStream dis = client.getDataInputStream();
		TextArea ta = client.getTextArea();
		try{
			while(client.getRunnable()){
				info = dis.readUTF();
				ta.append(info + "\n");
			}		
		}catch (IOException e) {
		}	
	} 	
}

 

import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
	public static void main(String args[]) {
		Hashtable<String,DataOutputStream> userList = new Hashtable<String,DataOutputStream>(); 
		String name;
		DataInputStream dis;
		DataOutputStream dos;
		try{
			ServerSocket ss = new ServerSocket(9999);
			while(true){
				Socket s = ss.accept();	
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				name = dis.readUTF();
				userList.put(name,dos);
				new MyServerReader(name,dis,userList).start();
			}
		}catch(Exception e){
			e.printStackTrace();	
		}
	}
}

class MyServerReader extends Thread{
	private String name;
	private DataInputStream dis;
	private Hashtable<String,DataOutputStream> userList;
	public MyServerReader(String name,DataInputStream dis,Hashtable<String,DataOutputStream> userList ){
		this.name = name;
		this.dis = dis;	
		this.userList = userList;
	}
	public void run(){
		String info;
		try{
			transmitMessage(name + " in!","--Server Info--");	
			while(true){
				info = dis.readUTF();
				if(info.equals("bye")){
					DataOutputStream dos = (DataOutputStream)(userList.get(name));
					Thread.sleep(1000);
					dos.close();
					dis.close();
					userList.remove(name);
					transmitMessage(name + " out!","--Server Info--");	
					break;
				}else if(info.length()>0){
					transmitMessage(info,name);	
				}
			}		
		}catch (Exception e) {
		}
	} 
	public void transmitMessage(String msg,String name){
		Collection doses = userList.values();
		DataOutputStream dos;
		for(Object o: doses){
			dos = (DataOutputStream)o;
			try{
				dos.writeUTF(name + ":" + msg);
			}catch(Exception e){
			}
		}			
	}		
}

 非阻塞式Socket通信

阻塞通信意味着通信方法在尝试访问套接字或者读写数据时阻塞了对套接字的访问。在 JDK 1.4 之前,绕过 阻塞限制的方法是无限制地使用线程,但这样常常会造成大量的线程开销,对系统的性能和可伸缩性产生影响。java.nio 包改变了这种状况,允许服务器有效地使用 I/O 流,在合理的时间内处理所服务的客户请求。
没有非阻塞通信,这个过程就像我所喜欢说的“为所欲为”那样。基本上,这个过程就是发送和读取任何能够发送/读取的东西。如果没有可以读取的东西,它就中止读操作,做其他的事情直到能够读取为止。当发送数据时,该过程将试图发送所有的数据,但返回实际发送出的内容。可能是全部数据、部分数据或者根本没有发送数据。
阻塞与非阻塞相比确实有一些优点,特别是遇到错误控制问题的时候。在阻塞套接字通信中,如果出现错误,该访问会自动返回标志错误的代码。错误可能是由于网络超时、套接字关闭或者任何类型的 I/O 错误造成的。在非阻塞套接字通信中,该方法能够处理的唯一错误是网络超时。为了检测使用非阻塞通信的网络超时,需要编写稍微多一点的代码,以确定自从上一次收到数据以来已经多长时间了
哪种方式更好取决于应用程序。如果使用的是同步通信,如果数据不必在读取任何数据之前处理的话,阻塞通信更好一些,而非阻塞通信则提供了处理任何已经读取的数据的机会。而异步通信,如 IRC 和聊天客户机则要求非阻塞通信以避免冻结套接字。

使用非阻塞实现I/O实现多用户聊天.

import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.awt.*;
import java.awt.event.*;

public class ChatClient {
	private SocketChannel sc = null;
	private String name = null;
	private Frame f;
	private TextArea ta;
	private TextField tf;
	private boolean runnable = true;

	public static void main(String[] args){
		ChatClient cc = new ChatClient();
		cc.createUI();
		cc.inputName();
		cc.connect();
		new ReceiveThread(cc,cc.getTextArea()).start();
	}
	public SocketChannel getSc(){
		return sc;	
	}
	public void setName(String name){
		this.name = name;
	}
	public TextArea getTextArea(){
		return ta;	
	}
	public TextField getTextField(){
		return tf;	
	}
	public boolean getRunnable(){
		return runnable;
	}	
	public void stop(){
		runnable = false;	
	}
	
	public void shutDown(){
		try{
			sc.write(ByteBuffer.wrap("bye".getBytes("GBK")));	
			ta.append("Exit in 5 seconds!");
			this.stop();
			Thread.sleep(5000);
			sc.close();
		}catch(Exception e){
			e.printStackTrace();	
		}
		System.exit(0);
	}
	
	public void createUI(){
		f = new Frame("Client");
		ta = new TextArea();
		ta.setEditable(false);
		tf = new TextField();
		Button send = new Button("Send");
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(tf,"Center");
		p.add(send,"East");
		f.add(ta,"Center");
		f.add(p,"South");
		MyClientListener listener = new MyClientListener(this);
		send.addActionListener(listener);
		tf.addActionListener(listener);
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				ChatClient.this.shutDown();
			}	
		});
		f.setSize(400,400);
		f.setLocation(600,0);
		f.setVisible(true);	
		tf.requestFocus();
	}
	
	public boolean connect(){
		try{
			sc = SocketChannel.open();
			//"zlg"为目标计算机名
			InetSocketAddress isa = new InetSocketAddress("zlg",8888);
			sc.connect(isa);
			sc.configureBlocking(false);
			sc.write(ByteBuffer.wrap(name.getBytes("GBK")));
		}catch(Exception e){
			e.printStackTrace();	
		}
		return true;
	}
	
	public void inputName(){
		String name = javax.swing.JOptionPane.showInputDialog("Input Your Name:");
		this.setName(name);	
		f.setTitle(name);
	}
}

class MyClientListener implements ActionListener{
	private ChatClient client;	
	public MyClientListener(ChatClient client){
		this.client = client;
	}
	public void actionPerformed(ActionEvent e){
		TextField tf = client.getTextField();
		String info = tf.getText();
		if(info.equals("bye")){
			client.shutDown();	
		}else{
			try{
				client.getSc().write(ByteBuffer.wrap(info.getBytes("GBK")));
			}catch (Exception e1) {
				e1.printStackTrace();		
			}		
		}
		tf.setText("");
		tf.requestFocus();		
	}	
}

class ReceiveThread extends Thread{
	private ChatClient client;
	private TextArea ta;
		
	public ReceiveThread(ChatClient client,TextArea ta){
		this.client = client;	
		this.ta = ta;
	}
	public void run(){
		SocketChannel sc = client.getSc();
		ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
		CharBuffer charBuffer = null;
		Charset charset = Charset.forName("GBK");
		CharsetDecoder decoder = charset.newDecoder();
		String msg = null;
		int n = 0;
		try{
			while(client.getRunnable()){
				n = sc.read(byteBuffer);
				if(n>0){
					byteBuffer.flip();
					charBuffer = decoder.decode(byteBuffer);
					msg = charBuffer.toString();
					ta.append(msg + "\n");
				}
				byteBuffer.clear();
				Thread.sleep(500);
			}
		}catch(Exception e){
			e.printStackTrace();
			System.exit(0);	
		}
	}
}

 

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;


public class ChatServer{
    private Selector selector = null;
    private ServerSocketChannel ssc = null;
    //服务器端通信端口号
    private int port = 8888;
    //在线用户列表
	private Hashtable<String,SocketChannel> userList = null;   
    
    public ChatServer(){}    
	public ChatServer(int port){
		this.port = port;
    }
    
    //初始化服务器
    public void init(){
    	try{
    		//创建选择器对象
			selector = Selector.open();
			//创建ServerSocketChannel
			ssc = ServerSocketChannel.open();
			//设置ServerSocketChannel为非阻塞模式
			ssc.configureBlocking(false);
			InetAddress ia = InetAddress.getLocalHost();
			InetSocketAddress isa = new InetSocketAddress(ia,port);
			//将与本通道相关的服务器套接字对象帮定到指定地址和端口
			ssc.socket().bind(isa);
			//创建在线用户列表
			userList = new Hashtable<String,SocketChannel>();
		}catch(IOException e){
			e.printStackTrace();	
		}
    }
    
    //启动服务器
	public void start(){
		try{
			//将ServerSocketChannel注册到Selector上,准备接收新连接请求
			SelectionKey acceptKey = ssc.register(selector, SelectionKey.OP_ACCEPT );
			SocketChannel sc;
			int n;	
			String name;   	//用户名
			String msg;		//用户发言信息
			while (true){	
				//选择当前所有处于就绪状态的通道所对应的选择键,并将这些键组成已选择键集
				n = selector.select(); //n为已选择键集中键的个数
		    	if(n > 0 ){
		    		//获取此选择器的已选择键集。
					Set readyKeys = selector.selectedKeys(); 
					Iterator it = readyKeys.iterator();	
					//遍历当前已选择键集
					while (it.hasNext()) {
						SelectionKey key = (SelectionKey)it.next();
						//从当前已选择键集中移除当前键,避免重复处理
						it.remove();
						//如果当前键对应的通道已准备好接受新的套接字连接
						if (key.isAcceptable()) {
							//获取当前键对应的可选择通道(ServerSocketChannel)  
							ssc = (ServerSocketChannel) key.channel();
							//接收新的套接字连接请求,返回新建的SocketChannel
							sc = (SocketChannel) ssc.accept();
							//如果有新用户接入
							if(sc != null){
								//接收新上线用户姓名
								name = readMessage(sc);
								//设置新建的SocketChannel为非阻塞模式
								sc.configureBlocking(false);
								//将新建的SocketChannel注册到Selector上,准备进行数据"写"操作,
								//并将当前用户名以附件的方式附带记录到新建的选择键上。
								SelectionKey newKey = sc.register(selector,SelectionKey.OP_WRITE,name);	
								//将新上线用户信息加入到在线用户列表
								userList.put(name,sc);
								//发送"新用户上线"通知
								transmitMessage(name + " in!","--Server Info--");
							}
						}
						//否则,如果当前键对应的通道已准备好进行"写"操作
						else if (key.isWritable()) {
							//获取当前键对应的可选择通道(SocketChannel) 
							sc = (SocketChannel)key.channel();
							//接收该通道相应用户的发言信息
							msg = readMessage(sc);
							//获取选择键上附带记录的当前用户名
							name = key.attachment().toString();
							//如果用户提出要下线
							if(msg.equals("bye")){
								//从在线用户列表中移除当前用户
								userList.remove(name);
								//注销当前选择键对应的注册关系
								key.cancel();
								//关闭当前可选择通道 
								sc.close();
								//发送"用户下线"通知
								transmitMessage(name + " out!","--Server Info--");
							}
							//否则,如果接收到的用户发言信息非空("")
							else if(msg.length() > 0){
								//转发用户发言信息
								transmitMessage(msg,name);
							}
						}
					}
				}
				//延时循环,降低服务器端处理负荷
				Thread.sleep(500);
			}
		}catch(Exception e){
			e.printStackTrace();	
		}
    }

	//转发用户发言信息
	public void transmitMessage(String msg,String name){
		try{
			ByteBuffer buffer = ByteBuffer.wrap((name + ":" + msg).getBytes("GBK"));
			Collection channels = userList.values();
			SocketChannel sc;
			for(Object o:channels){
				sc = (SocketChannel)o;
				sc.write(buffer);
				buffer.flip();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
    }
  
  	//接收用户发言信息
    public String readMessage(SocketChannel sc){
		String result = null;
		int n = 0;
        ByteBuffer buf = ByteBuffer.allocate(1024);
		try{
            n = sc.read(buf);
			buf.flip();
			Charset charset = Charset.forName("GBK");
			CharsetDecoder decoder = charset.newDecoder();
			CharBuffer charBuffer = decoder.decode(buf);
			result = charBuffer.toString();
        }catch(IOException e){
			e.printStackTrace();
		}
		return result;
    }

    public static void main(String args[]){
		ChatServer server = new ChatServer();
		server.init();
		server.start();
	}
}

 

 

分享到:
评论
1 楼 tianzhuowan 2011-02-16  
这是很好的学习资料,楼主辛苦了!

相关推荐

    Java网络编程第三版.pdf

    《Java网络编程第三版》是Java开发者深入理解网络编程的重要参考资料。这本书主要涵盖了Java平台上的网络应用程序开发,从基础概念到高级技术,为读者提供了一套全面的学习路径。以下是本书中涉及的一些关键知识点:...

    Windows网络编程.pdf

    Windows 网络编程 概述 Windows 网络编程是指在 Windows 操作系统平台上进行网络编程的技术,涉及到 Windows Socket、网络协议、网络应用程序的开发等方面。 Windows 网络编程的主要目的是实现高性能的网络应用...

    TCP IP网络编程

    扫描版 超清百度网盘资源!!! 为初学者准备的网络编程! 韩国TCP/IP经典教程!... 本书针对网络编程初学者,面向具备C语言基础的套接字网络编程学习者,适合所有希望学习Linux和Windows网络编程的人。

    C++网络编程文档

    C++网络编程是计算机科学中的一个重要领域,它允许开发者创建能够通过网络进行通信的应用程序。这份"C++网络编程文档"涵盖了这一主题的广泛内容,旨在帮助程序员深入理解并掌握网络编程的基本概念和技术。 首先,...

    Unix网络编程英文版PDF

    《Unix网络编程》是学习Unix系统下网络编程的重要书籍。这本书的英文版由Addison-Wesley出版社出版,是UNIX Network Programming系列的第一卷,第三版。在第三版中,作者对第二版内容进行了更新,添加了对新的编程...

    c#网络编程实例教程源代码

    《C#网络编程实例教程源代码》是一份深入浅出的教学资源,旨在帮助开发者掌握C#语言在网络编程领域的应用。这份教程结合了理论与实践,提供了丰富的源代码示例,让学习者能够通过实际操作来理解和掌握网络编程的核心...

    Linux网络编程教程pdf完整版

    《Linux网络编程教程》这本书是Linux系统中进行网络编程的重要参考资料。它涵盖了广泛的知识点,旨在帮助读者理解和掌握如何在Linux环境下开发网络应用程序。以下是对这些主题的详细阐述: 1. **网络编程基础**:...

    java网络编程第四版pdf

    《Java网络编程(第四版)》是一本深入探讨Java在互联网环境下的编程技术的经典书籍。本书旨在帮助读者理解和掌握如何利用Java语言进行高效、安全的网络通信。书中内容覆盖了从基本的网络概念到复杂的多线程编程,是...

    c++网络编程实例.pdf

    C++ 网络编程实例 本文档提供了 C++ 网络编程的基础知识,涵盖了网络编程的概述、OSI 七层网络模型、TCP/IP 协议和 C/S 编程模型等内容。 网络编程概述 网络编程是指用户使用 MFC 类库在 VC 编译器中编写程序,以...

    Linux网络编程,包括tcp/upd,select/poll/epoll/pdf

    linux网络编程 pdf # Linux网络编程基础 Linux网络编程是指在Linux操作系统上开发网络应用程序的过程。它主要涉及到TCP/UDP协议以及select/poll/epoll等多路复用技术。 TCP/UDP协议是网络通信的基础,其中TCP协议...

    Java网络编程(第4版)PDF

    《Java网络编程(第4版)》是一本深入探讨Java平台上的网络编程技术的专业书籍,适合想要提升Java通讯技术的学者阅读。此书全面覆盖了Java网络编程的基础和高级概念,帮助开发者理解如何利用Java语言构建高效、可靠的...

    Java网络编程实验报告.pdf

    "Java网络编程实验报告" 本实验报告主要介绍了Java网络编程的基本概念和实现方法,通过设计和实现一个简单的客户端/服务器应用程序,了解Java网络编程的基本原理和实现方法。 知识点1:Java 网络编程基础 Java ...

    Java网络编程案例教程习题参考答案 .pdf

    Java网络编程案例教程习题参考答案 Java_network_programming是Java编程语言中一个基础组件,用于实现网络通信。以下是Java网络编程案例教程习题参考答案中涉及到的知识点: 1. Socket编程:Socket是Java网络编程...

    unix网络编程三卷合一中文版

    《Unix网络编程》是一套由美国著名计算机科学家W. Richard Stevens撰写的经典教材,涵盖了Unix系统下的网络编程各个方面。这套书共分为三卷,每卷都深入探讨了其主题,对于理解和掌握网络编程技术具有极高的参考价值...

    UNIX网络编程第1卷(1-19章)

    《UNIX网络编程》第一卷主要涵盖了网络编程的基本概念、传输层协议TCP和UDP的细节、套接口编程的原理与应用,以及高级网络编程技术。该书是网络编程领域的经典之作,作者是著名的网络编程专家W. Richard Stevens。...

    Visual C++网络编程案例实战.pdf

    《Visual C++网络编程案例实战》一书深入探讨了如何利用Visual C++及MFC类库进行网络编程,尤其强调了Windows Socket的应用。本书不仅覆盖了理论基础,还提供了丰富的实践案例,帮助读者掌握网络编程的核心技能。 #...

    IT公司笔试\linux c网络网络编程面试题收集

    Linux C 网络编程面试题收集 本文总结了 Linux C 网络编程面试题,涵盖了基础知识、网络编程、路由等方面的知识点,旨在帮助读者更好地理解和掌握相关知识。 一、基础知识 1. 对于程序 `func(char *str){printf(...

    C#网络编程高级篇之网页游戏辅助程序设计.part3_C#_网络编程_

    这本书是关于c#网络编程的,关于c#入门的书有很多,但是关于c#网络编程的并不多,很多教材中虽有涉及网络编程但都是泛泛而谈,很多理论概念掺杂在其中,让人很难理解,而这本不同,含有非常多的例子,从简到深,甚至...

    Unix 网络编程 卷1 第三版 源代码

    《UNIX网络编程》(第1卷)(套接口API第3版)第1版和第2版由已故UNIX网络专家W. Richard Stevens博士独自编写。《UNIX网络编程》(第1卷)(套接口API第3版)是3版,由世界著名网络专家Bill Fenner和Andrew M. Rudoff执笔,...

    UNIX环境高级编程+UNIX网络编程卷1.PDF版

    《UNIX环境高级编程》与《UNIX网络编程卷1:协议》是两本深入解析UNIX系统编程的经典著作。在深入理解这些书籍的知识点之前,我们先要了解UNIX系统的基础概念。 UNIX是一个多用户、多任务的操作系统,其设计哲学...

Global site tag (gtag.js) - Google Analytics