Java网络编程

Java网络编程

java网络编程基础知识

1、协议(TCP/IP)

     TCP/IP(Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。

TCP/IP协议的由来

     在阿帕网(ARPR)产生运作之初,通过接口信号处理机实现互联的电脑并不多,大部分电脑相互之间不兼容,在一台电脑上完成的工作,很难拿到另一台电脑上去用,想让硬件和软件都不一样的电脑联网,也有很多困难。当时美国的状况是,陆军用的电脑是DEC系列产品,海军用的电脑是Honeywell中标机器,空军用的是IBM公司中标的电脑,每一个军种的电脑在各自的系里都运行良好,但却有一个大弊病:不能共享资源。

 

互联网之父--瑟夫(Vinton G.Cerf)

1997年,为了褒奖对因特网发展作出突出贡献的科学家,并对TCP/IP协议作出充分肯定,美国授予为因特网发明和定义TCP/IP协议的文顿·瑟夫和卡恩“国家技术金奖”。这无疑使人们认识到TCP/IP协议的重要性。

Java网络编程_第1张图片

tcp/ip基础--ip地址与包的路由传递

ip地址

概述:每个internet上的主机和路由器都有一个ip地址,它包括网络号和主机号,所有ip地址都是32位的,ip地址按照国际标准的划分为a,b,c,d,e五种类型。

 

端口(port)--概念

    在网络技术中,端口(Port)有好几种意思。集线器、交换机、路由器的端口指的是连接其他网络设备的接口,如RJ-45端口、Serial端口等。这里所指的端口不是指物理意义上的端口,而是特指TCP/IP协议中的端口,是逻辑意义上的端口。

    如果把IP地址比作一间房子,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口可以有65536(即:256*256)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0到65535(256*256-1)。

 

端口(port)--分类

有65536个端口0号是保留端口

1-1024是固定端口

又叫有名端口,即被某些程序固定使用,一般程序员不使用。

22:SSH远程登录协议 23:telnet使用 21:ftp使用

25:smtp服务使用 80:iis使用 7:echo服务

1025-65535是动态端口

这些端口,程序员可以使用

 

端口(port)--注意事项

1、在计算机(尤其是做服务器)要尽可能的少开端口;

2、一个端口只能被一个程序监听;

3、如果使用netstat -an可以查看本机有哪些端口在监听

4、可以使用netstat -anb来查看监听端口的pid,在结合任务管理器关闭不需要的端口。

 

url--概念

     统一资源定位符(URL,Uniform Resource Locator的缩写)也被称为网页地址,是因特网上标准的资源的地址。它最初是由蒂姆·伯纳斯-李发明用来作为万维网的地址的。现在它已经被万维网联盟编制为因特网标准RFC1738了。

     Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL地址,这种地址可以是本地磁盘,也可以是局域网上的某一台计算机,更多的是Internet上的站点,简单地说,URL就是Web地址,俗称“网址”,是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。

 

url--组成

http://www.sina.com:8080/index.html

1、协议;2、ip地址(32位);3、端口号(16位)0-65535;4、资源名称。

 

单工、半双工和全双工

     如果甲可以向乙发送数据,但是乙不能向甲发送数据,这样的通信就是单工通信(Simplex Communication)。

     单工数据传输只支持数据在一个方向上传输,就和传呼机一样。

     半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信,就和对讲机一样;

全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力,就和电话一样。

Java网络编程_第2张图片

案例一:半双工

Server1.java
/**
 * 半双工
 * 服务器端,9999端口监听
 * 可以接收从客户端发来的信息
 */
package com.net.server;

import java.io.IOException;
import java.net.*;
import java.io.*;

public class Server1 {
	ServerSocket ss = null;
	Socket s = null;

	// 构造方法
	public Server1()   {
		try {
			// 在9999端口进行监听
			ss = new ServerSocket(9999);
			// 等待某个客户端来连接,该方法会返回一个Socket连接
			s = ss.accept();

			// 读取s中传递的数据
			InputStreamReader isr = new InputStreamReader(s.getInputStream());
			BufferedReader br = new BufferedReader(isr);

			String info = br.readLine();
			System.out.println("服务器接收到了" + info);

			PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
			pw.println("Hello,Client!");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (s != null) {
					s.close();
				}
				if (ss != null) {
					ss.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Server1 s1 = new Server1();
	}

}

Client1.java
/**
 * 客户端
 */
package com.net.client;
import java.io.IOException;
import java.net.*;
import java.io.*;
public class Client1 {
	Socket s = null;
	//构造方法
	public Client1(){
		try {
			//Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,9999是该服务器的端口号
			s = new Socket("127.0.0.1", 9999);
			//连接成功,就可以发送数据给服务器
			//通过PrintWriter向s写数据,true表示即时刷新
			PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
			pw.println("Hello,Server!");
			
			InputStreamReader isr = new InputStreamReader(s.getInputStream());
			BufferedReader br = new BufferedReader(isr);
			
			String resp = br.readLine();
			System.out.println("客户端接收到了" + resp);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(s != null){
					s.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		Client1 c1 = new Client1();
	}

}


案例二:半双工聊天

Server2.java
/**
 * 半双工
 * 服务器端,9999端口监听
 * 可以接收从客户端发来的信息
 */
package com.net.server;

import java.net.*;
import java.io.*;

public class Server2 {
	ServerSocket ss = null;
	Socket s = null;
	BufferedReader br1 = null;
	BufferedReader br2 = null;
	PrintWriter pw = null;

	// 构造方法
	public Server2() {
		try {
			// 在9999端口进行监听
			ss = new ServerSocket(9999);
			// 等待某个客户端连接,返回 Socket
			s = ss.accept();

			while (true) {
				// 从客户端接收消息
				br1 = new BufferedReader(new InputStreamReader(
						s.getInputStream()));
				String str = br1.readLine();
				System.out.println("从客户端收到的消息是:" + str);
				// 如果收到消息为"byebye",关闭服务器
				if (str.equals("byebye")) {
					System.out.println("服务器关闭连接");
					break;
				}

				// 从控制台输入
				System.out.print("从控制台输入:");
				br2 = new BufferedReader(new InputStreamReader(System.in));
				// 将消息发送给客户端
				pw = new PrintWriter(s.getOutputStream(), true);
				pw.println(br2.readLine());
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭资源
				if (pw != null) {
					pw.close();
				}
				if (br2 != null) {
					br2.close();
				}
				if (br1 != null) {
					br1.close();
				}
				if (s != null) {
					s.close();
				}
				if (ss != null) {
					ss.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Server2 s2 = new Server2();
	}
}

Client2.java
/**
 * 客户端
 */
package com.net.client;

import java.net.*;
import java.io.*;

public class Client2 {
	Socket s = null;
	PrintWriter pw = null;
	BufferedReader br1 = null;
	BufferedReader br2 = null;

	public Client2() {
		try {
			// Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,9999是该服务器的端口号
			s = new Socket("127.0.0.1", 9999);
			while (true) {
				// 连接成功,就可以发送数据给服务器
				// 从控制台读入数据
				System.out.print("从控制台输入:");
				br1 = new BufferedReader(new InputStreamReader(System.in));
				String str = br1.readLine();
				// 通过PrintWriter向s写数据,true表示即时刷新
				pw = new PrintWriter(s.getOutputStream(), true);
				pw.println(str);
				if (str.equals("byebye")) {
					System.out.println("客户端关闭连接");
					break;
				}

				// 从服务端接收消息
				br2 = new BufferedReader(new InputStreamReader(
						s.getInputStream()));
				System.out.println("从服务器接收的消息是:" + br2.readLine());
			}

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭资源
				if (pw != null) {
					pw.close();
				}
				if (br2 != null) {
					br2.close();
				}
				if (br1 != null) {
					br1.close();
				}
				if (s != null) {
					s.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Client2 c2 = new Client2();
	}

}


案例三:全双工聊天

Server3.java
/**
 * 全双工
 * 监听端口6166
 */
package com.net.server;

import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.RenderingHints.Key;

import javax.swing.*;
import java.awt.event.*;

public class Server3 extends JFrame implements ActionListener, KeyListener {

	// 网络变量
	ServerSocket ss = null;
	Socket s = null;

	// IO流
	BufferedReader br = null;
	PrintWriter pw = null;

	// 定义组件
	JTextArea jta = null;
	JTextField jtf = null;
	JButton jb = null;
	JPanel jp1 = null;
	JScrollPane jsp = null;

	// 构造方法
	public Server3() {
		// 创建组件
		jta = new JTextArea();
		jsp = new JScrollPane(jta);
		jtf = new JTextField(20);
		jtf.addKeyListener(this);
		jb = new JButton("发送");
		jb.addActionListener(this);
		jp1 = new JPanel();

		// 添加到JPanel
		jp1.add(jtf);
		jp1.add(jb);

		// 添加到JFrame
		add(jsp, "Center");
		add(jp1, "South");

		// 设置窗体
		setTitle("服务器端");
		setSize(400, 300);
		setLocation(0, 100);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);

		try {
			// 服务器监听
			ss = new ServerSocket(6166);
			// 等待客户端连接
			s = ss.accept();

			// 创建读入缓冲字符流
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			// 创建打印流
			pw = new PrintWriter(s.getOutputStream(), true);

			while (true) {
				// 读取从客户端发来的信息
				// 当没有消息过来时,会一直处于阻塞状态,这条语句也就不会执行
				String info = br.readLine();
				jta.append("客户端:" + info + "\r\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Server3 s3 = new Server3();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == jb) {
			// 点击确定,发送信息
			// 把服务器在jtf写的内容发送给客户端,并在jta显示
			String info = jtf.getText();
			pw.println(info);
			jta.append("服务器:" + info + "\r\n");
			jtf.setText("");
		}

	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			// 按下Enter,发送信息
			// 把服务器在jtf写的内容发送给客户端,并在jta显示
			String info = jtf.getText();
			pw.println(info);
			jta.append("服务器:" + info + "\r\n");
			jtf.setText("");
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}

}

Client3.java
/**
 * 客户端
 */
package com.net.client;

import java.net.*;
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Client3 extends JFrame implements ActionListener, KeyListener {
	// 网络变量
	Socket s = null;

	// IO流
	BufferedReader br = null;
	PrintWriter pw = null;

	// 定义组件
	JTextArea jta = null;
	JTextField jtf = null;
	JButton jb = null;
	JPanel jp1 = null;
	JScrollPane jsp = null;

	// 构造方法
	public Client3() {
		// 创建组件
		jta = new JTextArea();
		jsp = new JScrollPane(jta);
		jtf = new JTextField(20);
		jtf.addKeyListener(this);
		jb = new JButton("发送");
		jb.addActionListener(this);
		jp1 = new JPanel();

		// 添加到JPanel
		jp1.add(jtf);
		jp1.add(jb);

		// 添加到JFrame
		add(jsp, "Center");
		add(jp1, "South");

		// 设置窗体
		setTitle("客户端");
		setSize(400, 300);
		setLocation(500, 100);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);

		try {
			// Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,6166是该服务器的端口号
			s = new Socket("127.0.0.1", 6166);
			// 创建读入缓冲字符流
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			// 创建打印流
			pw = new PrintWriter(s.getOutputStream(), true);

			while (true) {
				// 读取从服务器发来的消息
				// 当没有消息过来时,会一直处于阻塞状态,这条语句也就不会执行
				String info = br.readLine();
				jta.append("服务器:" + info + "\r\n");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭资源
				if (pw != null) {
					pw.close();
				}
				if (br != null) {
					br.close();
				}
				if (s != null) {
					s.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Client3 c3 = new Client3();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == jb) {
			// 如果点击确定按钮
			// 发送给服务端,并更新jtf,并在jta显示
			String info = jtf.getText();
			pw.println(info);
			jta.append("客户端:" + info + "\r\n");
			jtf.setText("");
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			// 按下Enter,发送信息
			// 把服务器在jtf写的内容发送给客户端,并在jta显示
			String info = jtf.getText();
			pw.println(info);
			jta.append("服务器:" + info + "\r\n");
			jtf.setText("");
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}

}

 

案例四:在网络间传递对象

User.java
/**
 * 对象流所用对象
 * 必须序列化
 */
package com.objectstream;

import java.io.*;

public class User implements Serializable {
	private String name;
	private String pass;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPass() {
		return pass;
	}

	public void setPass(String pass) {
		this.pass = pass;
	}

}

Server1.java
/**
 * 对象流
 * 服务器
 * 监听端口1234
 */
package com.objectstream;

import java.net.*;
import java.io.*;

public class Server1 {
	ServerSocket ss = null;
	Socket s = null;
	ObjectInputStream ois = null;

	// 构造方法
	public Server1() {
		try {
			ss = new ServerSocket(1234);
			s = ss.accept();
			System.out.println("在1234端口监听");
			// 以对象流方式读取(假定客户端发送的是User的一个对象)
			ois = new ObjectInputStream(s.getInputStream());
			User u = (User) ois.readObject();

			// 输出
			System.out.println("从客户端接收到了" + u.getName() + " " + u.getPass());

		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (ois != null) {
					ois.close();
				}
				if (s != null) {
					s.close();
				}
				if (ss != null) {
					ss.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Server1 s1 = new Server1();
	}

}

Client1.java
/**
 * 客户端
 */
package com.objectstream;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client1 {
	Socket s = null;
	ObjectOutputStream oos = null;

	// 构造方法
	public Client1() {
		try {
			s = new Socket("127.0.0.1", 1234);
			// 通过ObjectOutputStream给服务器传递对象
			oos = new ObjectOutputStream(s.getOutputStream());
			User u = new User();
			u.setName("张三");
			u.setPass("123456");
			oos.writeObject(u);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (oos != null) {
					oos.close();
				}
				if (s != null) {
					s.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Client1 c1 = new Client1();
	}
}

特别说明:

在java络编程要通过IO流实现对象的传递需要对服务端和客户端定义相同的对象,以达到实现对象的传递需要进行Serializable序列化,否则报错。


----------参考《韩顺平.循序渐进学.java.从入门到精通》

----------参考《JDK_API_1_6_zh_CN

Java学习笔记--导航http://blog.csdn.net/q547550831/article/details/49819641



















你可能感兴趣的:(java,网络编程,实例,IO流,对象流)