Java之网络编程笔记
网络通讯要素:
1.IP地址
IP地址:用于标记一台计算机的身份证。 IP地址由网络地址(确定网络)和主机地址(网络中的主机)组成。
IP地址分为A类地址、B类地址、C类地址(常用)、D类地址、E类地址。
子网掩码:为了区分网络地址和主机地址。 127.0.0.1(localhost)是本机地址。
IPV4和IPV6:IPV4使用4个十进制数表示,即32位二进制。
测试网卡:ping 127.0.0.1 若出现问题,就说明网卡出问题
2.端口号
web服务器:80
mysql默认:3306
3.传输协议
UDP(要明确对方地址和端口)(只管发,不管收)
*面向无连接
*数据会被封包,包体积有限,限制在64K以内
*因面向无连接,故为不可靠协议
*速度快
示例:聊天,视频会议,桌面共享
TCP
*面向连接
*通过三次握手完成连接,是可靠协议
*在连接中进行大数据量传输
*必须建立连接,效率会稍低
示例:打电话,下载
4.SMTP:简单邮件传输协议 ,端口号是25.
FTP:文件传输协议 ,端口号是21.
Http:超文本传输协议 ,端口号是80.
telnet用于连接远程计算机或者因特网计算机提供的服务。每个服务都会设定一个端口。
和特定的服务进行通信: 在cmd中使用命令 telnet ip port 。
如果要连接因特网的服务,不仅要给出端口,还要给出计算机的名称,只有给出IP地址和端口号时,才能够请求服务,并接收到应答。
URL和URI
URI:统一资源标识符,用于标识一个web资源,包含了两个部分。
(1)URL:统一资源定位符。能够精确的定位数据的URI
(2)URN:统一资源名称。除了URL的URI
在java中URI和URL是分开的两个类,URI类专门用于解析,URL用于通信。
URL
1.URI分类
绝对和相对:
(1)绝对URI是指有确定的协议。比如http,ftp。后面以/进行分隔
(2)相对URI是没有scheme的。
透明和不透明:
(1)不透明URI是不能够被解析的URI。不透明URI是绝对URI。scheme后面的部分不是以/进行分割。
分层和不分层:
(1)分层是绝对透明URI或相对URI。
所有的网页端口都是80.
2.URI的作用:
(1)解析
URI的格式:
[scheme:]scheme-specific-part[#fragment]
scheme表示用的协议,可以是http\https\ftp\file等。
scheme-specific-part是其余部分。
进一步细分:
[scheme:][//authority][path][?query][#fragment]
常用方法:
- getScheme()获得scheme;
- getSchemeSpecificPart()
- getPath()
- getAuthority()
(2)相对标识符和绝对标识符的转换
resolve和relative函数。
示例代码:
任务1:取得特定网址的html代码。
任务2:分析地址信息。
任务3:绝对地址和相对地址转换
- package org.core;
- import java.net.*;
- import java.util.*;
- public class URLTest1 {
- public static void main(String[] args) throws Exception {
- URL url = new URL("http://www.ecnu.edu.cn");
- Scanner in = new Scanner(url.openStream());
- while (in.hasNextLine()) {
- String str = in.nextLine();
- System.out.println(str);
- }
- URI uri = new URI("http://blog.csdn.net/xiazdong");
- System.out.println(uri.getScheme());
- System.out.println(uri.getSchemeSpecificPart());
- System.out.println(uri.getAuthority());
- System.out.println(uri.getUserInfo());
- System.out.println(uri.getHost());
- System.out.println(uri.getPort());
- System.out.println(uri.getPath());
- System.out.println(uri.getQuery());
- System.out.println(uri.getFragment());
- String str = "/article/details/6705033";
- URI combined = uri.resolve(str);// 根据uri的路径把str变成绝对地址
- System.out.println(combined.getScheme()
- + combined.getSchemeSpecificPart());
- URI relative = uri.relativize(new URI(str));
- System.out.println(relative.getSchemeSpecificPart());
- }
- }
URL和URLConnection
URL的作用
1.如果想要获取某个网页的html源代码,比如http://blog.csdn.net/xiazdong 则只需要:
(1)URL url = new URL("http://blog.csdn.net/xiazdong");
(2)Scanner in = new Scanner(url.openStream());
即可.
2.获取消息头信息
- URLConnection connection = url.openConnection();
- connection.getHeaderFields()返回一个Map<String,List<String>>
- connection.getContentLength();
- connection.getContentType();
- connection.setDoOutput(true)获得输出流
- connection.getOutputStream();
- connection.getInputStream();
代码示例:
- package org.core;
- import java.net.*;
- import sun.misc.*;
- import java.util.*;
- import java.io.*;
- public class URLConnectionTest {
- public static void main(String[] args) throws Exception {
- String urlName = "http://java.sun.com";
- URL url = new URL(urlName);
- URLConnection connection = url.openConnection();
- Map<String, List<String>> map = connection.getHeaderFields();
- for (Map.Entry<String, List<String>> entry : map.entrySet()) {
- String key = entry.getKey();
- List<String> value = entry.getValue();
- System.out.println(key + ":" + value);
- }
- }
- }
在网页中如果要提交数据给web服务器,通常要把数据发送给web服务器,然后web服务器委派一个脚本对数据进行处理,返回一个相应。
通常发送数据的方法有两种:get和post。
(1)get方法是直接把数据跟在url的后面,以name=value进行传输,
每个数据之间用&进行分割,value中的空格用+替换,非字母数字用%替换,并后跟两个16进制数,这种编码方式称为URL编码。URLEncoder和URLDecoder
(2)post方法是通过URLConnection发送给服务器,编码方式和get一样。URLEncoder.encode(VALUE,"UTF-8");
一般在传输中文时会运用编码和解码。
示例:通过URLEncoder和URLDecoder编码和解码
略
InetAddress 根据域名得到IP地址或名称
没有构造方法,通过:
(1)InetAddress i1 = InetAddress.getByName(String)返回一个InetAddress实例。
(2)如果一个地址有多个ip地址,比如google,有3个ip地址,就调用InetAddress[] i2 = InetAddress.getAllByName(String);
InetAddress.getLocalhost()获得本机的InetAddress实例。
代码实例:
- package org.core;
- import java.net.InetAddress;
- public class InetAddressTest {
- public static void main(String[] args) throws Exception{
- InetAddress local = InetAddress.getLocalHost();
- System.out.println("本机地址:"+local.getHostAddress());
- System.out.println("本机名称:"+local.getHostName());
- InetAddress[] remote = InetAddress.getAllByName("www.google.com");
- for(InetAddress a : remote)
- {
- System.out.println("地址:"+a.getHostAddress());
- System.out.println("名称:"+a.getHostName());
- }
- }
- }
Socket(TCP)
Socket是一个用于机器之间通信的类。
Socket客户端:
(1)Socket s = new Socket(ip,port);打开一个套接字,发送请求
(2)InputStream istream = s.getInputStream();接收数据
(3)OutputStream ostream = s.getOutputStream();发送数据
需要用PrintWriter和Scanner进行包装,并且注意PrintWriter的自动缓冲。
Socket服务器:注意多个客户端同时访问服务器的问题:多线程
(1)ServerSocket server = new ServerSocket(port);创建一个端口
(2)Socket s = server.accept(); 只有当有客户端请求并连接,函数才会返回
(3)InputStream istream = s.getInputStream();接收数据
(4)OutputStream ostream = s.getOutputStream();发送数据
需要用PrintWriter和Scanner进行包装,并且注意PrintWriter的自动缓冲。
我们在使用PrintWriter时需要使用println()函数;
当服务器或客户端任意一方请求结束通信,则立刻停止。
问题1:在套接字中会发生阻塞的地方:
(1)实例化Socket时,会阻塞。
(2)在in.nextLine()类似操作时会阻塞。
解决方法:
(1)对于第一个问题,解决方法:
- Socket s = new Socket();建立无连接socket
- s.connect(new InetSocketAddress(host,port),timeout);设置超时。
(2)对于第二个问题,解决方法是设置s.setSoTimeout(long)设置超时时间
问题2:当客户端想要关闭套接字时,但却不能确定服务器是否还在发送数据,但是只要一关闭就立刻断开。
解决方法:
socket.shutdownOutput()关闭输出流
socket.shutdownInput()关闭输入流
半关闭示例代码:客户端发送hello给服务器,同时关闭输出流,服务器接收到后关闭输入流,等待5秒发送ECHO hello给客户端。
Client:
- import java.net.*;
- import java.io.*;
- import java.util.*;
- public class shutdownOutputClient {
- public static void main(String[] args)throws Exception {
- Socket s = new Socket("localhost",8819);
- Scanner in = new Scanner(s.getInputStream());
- PrintWriter out = new PrintWriter(s.getOutputStream(),true);
- out.println("Hello");//输出hello
- s.shutdownOutput(); //关闭输出流
- System.out.println("关闭连接");
- while(in.hasNextLine()){
- System.out.println(in.nextLine());
- }
- s.close();
- }
- }
Server:
- import java.net.*;
- import java.io.*;
- import java.util.*;
- public class shutdownOutputServer {
- public static void main(String[] args)throws Exception {
- ServerSocket server = new ServerSocket(8819);
- Socket s = server.accept();
- Scanner in = new Scanner(s.getInputStream());
- PrintWriter out = new PrintWriter(s.getOutputStream(),true);
- String str = in.nextLine();
- System.out.println(str);
- s.shutdownInput();
- System.out.println("关闭输入流");
- Thread.sleep(5000);
- out.println("Echo:"+str);
- s.close();
- }
- }
综合代码举例:实现一个简单的对等通信程序,通过多线程,一个线程接收数据,一个线程发送数据。
用户1:
- import java.util.*;
- import java.io.*;
- import java.net.*;
- public class Client{
- public static void main(String[]args)throws Exception{
- Socket s = new Socket("localhost",8819);
- PrintWriter out = new PrintWriter(s.getOutputStream(),true);
- Thread t = new Thread(new Receive(s));
- t.start();
- //以下代码用于发送数据
- Scanner in = new Scanner(System.in);//键盘输入
- while(in.hasNextLine()){ //一直不断
- out.println(in.nextLine()); //发送键盘输入数据
- }
- }
- }
- class Receive implements Runnable //这个类用于接收数据
- {
- private Socket s;
- public Receive(Socket s)
- {
- this.s = s;
- }
- public void run()
- {
- try{
- Scanner in = new Scanner(s.getInputStream()); //in:接收数据
- String str = null;
- while(true)
- {
- str = in.nextLine();
- System.out.println("服务器说:"+str); //打印接收数据
- }
- }
- catch(Exception e){}
- }
- }
用户2:
- import java.util.*;
- import java.io.*;
- import java.net.*;
- public class Server{
- public static void main(String[]args)throws Exception{
- ServerSocket server = new ServerSocket(8819);
- Socket s = server.accept();
- PrintWriter out = new PrintWriter(s.getOutputStream(),true);
- Thread t = new Thread(new Receive1(s));
- t.start();
- //以下代码用于发送数据
- Scanner in = new Scanner(System.in);//键盘输入
- while(in.hasNextLine()){ //一直不断
- out.println(in.nextLine()); //发送键盘输入数据
- }
- }
- }
- class Receive1 implements Runnable //这个类用于接收数据
- {
- private Socket s;
- public Receive1(Socket s)
- {
- this.s = s;
- }
- public void run()
- {
- try{
- Scanner in = new Scanner(s.getInputStream()); //in:接收数据
- String str = null;
- while(true)
- {
- str = in.nextLine();
- System.out.println("客户端说:"+str); //打印接收数据
- }
- }
- catch(Exception e){}
- }
- }
以上的程序属于C/S,需要同时维护客户端和服务器的代码。
B/S:浏览器和服务器,只需要维护一方代码即可。
聊天工具使用UDP非常多,因为我们通常也会遇到我们发给另一个人一条消息,另一个人却没有收到的情况。
DatagramPacket和DatagramSocket 数据报
代码举例:实现服务器发送数据报到客户端。
Client:
- package org.core;
- import java.net.*;
- import java.io.*;
- public class DatagramClient {
- public static void main(String[] args) throws Exception{
- byte[]buf = new byte[1024];
- DatagramPacket packet = new DatagramPacket(buf,1024);
- DatagramSocket client = new DatagramSocket(9000);
- client.receive(packet);
- String str = new String(buf,0,packet.getLength());
- System.out.println(packet.getAddress().getHostName()+":"+str);
- client.close();
- }
- }
Server:
- package org.core;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- public class DatagramServer {
- public static void main(String[] args)throws Exception {
- DatagramSocket server = new DatagramSocket(3000);
- String str = "hello world";
- DatagramPacket packet = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getLocalHost(),9000);
- server.send(packet);
- server.close();
- }
- }
QQ聊天应用
Server端
- package org.xiazdong.server;
- import java.awt.BorderLayout;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.io.PrintStream;
- import java.net.InetAddress;
- import java.net.ServerSocket;
- import java.net.Socket;
- import javax.swing.JButton;
- import javax.swing.JFrame;
- import javax.swing.JPanel;
- import javax.swing.JScrollPane;
- import javax.swing.JTextArea;
- import javax.swing.JTextField;
- public class Server3 extends JFrame{
- static JTextArea area;
- JTextField field;
- JButton button;
- static PrintStream writer;
- public Server3(){
- this.setTitle("服务器");
- this.setSize(400,500);
- area = new JTextArea(25,30);
- area.setEditable(false);
- field = new JTextField(20);
- button = new JButton("提交");
- JPanel panel = new JPanel();
- JScrollPane sp = new JScrollPane(area);
- this.add(sp,BorderLayout.CENTER);
- panel.add(field);
- panel.add(button);
- this.add(panel,BorderLayout.SOUTH);
- this.setVisible(true);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- button.addActionListener(new ActionListener(){
- @Override
- public void actionPerformed(ActionEvent e) {
- String text = field.getText();
- writer.println(text);
- area.append("我:"+text+"\n");
- field.setText("");
- }
- });
- }
- public static void main(String[] args) throws Exception {
- Server3 s = new Server3();
- ServerSocket server = new ServerSocket(8899);
- System.out.println("开始监听...");
- Socket socket = server.accept();
- InetAddress address = socket.getInetAddress();
- String name = address.getLocalHost().getHostName();
- System.out.println(name+"已连接");
- BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- writer = new PrintStream(socket.getOutputStream(), true);
- while (true) {
- String line = null;
- line = reader.readLine();
- if (line != null) {
- area.append("客户端:"+line+"\n");
- }
- }
- }
- }
Client端
- package org.xiazdong.client;
- import java.awt.BorderLayout;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.net.Socket;
- import javax.swing.JButton;
- import javax.swing.JFrame;
- import javax.swing.JPanel;
- import javax.swing.JScrollPane;
- import javax.swing.JTextArea;
- import javax.swing.JTextField;
- public class Client3 extends JFrame{
- static JTextArea area;
- JTextField field;
- JButton button;
- static PrintWriter writer;
- public Client3(){
- this.setTitle("客户端");
- this.setSize(400,500);
- area = new JTextArea(25,30);
- area.setEditable(false);
- field = new JTextField(20);
- button = new JButton("提交");
- JScrollPane sp = new JScrollPane(area);
- JPanel panel = new JPanel();
- this.add(sp,BorderLayout.CENTER);
- panel.add(field);
- panel.add(button);
- this.add(panel,BorderLayout.SOUTH);
- this.setVisible(true);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- button.addActionListener(new ActionListener(){
- @Override
- public void actionPerformed(ActionEvent e) {
- String text = field.getText();
- writer.println(text);
- area.append("我:"+text+"\n");
- field.setText("");
- }
- });
- }
- public static void main(String[] args) throws Exception{
- Client3 c = new Client3();
- Socket socket = new Socket("127.0.0.1",8899);
- OutputStream out = socket.getOutputStream();
- BufferedReader reader1 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- writer = new PrintWriter(out,true);
- System.out.println("已经成功和服务器连接...");
- while(true){
- String line = reader1.readLine();
- area.append("服务器:"+line+"\n");
- }
- }
- }
PrintWriter的autoflush
如果PrintWriter writer = new PrintWriter(out,true);
则调用println()、printf()、format()函数时会自动刷新,其他函数都不会,比如write()、print()函数时不会自动刷新
网络编程常见异常
第
1个异常是java.net.BindException:Address already in use:
JVM_Bind。该异常发生在服务器端进行new
ServerSocket(port)(port是一个0,65536的整型值)操作时。异常的原因是以为与port一样的一个端口已经被启动,并进行监
听。此时用netstat
–an命令,可以看到一个Listending状态的端口。只需要找一个没有被占用的端口就能解决这个问题。
第
2个异常是java.net.ConnectException: Connection refused:
connect。该异常发生在客户端进行new Socket(ip,
port)操作时,该异常发生的原因是或者具有ip地址的机器不能找到(也就是说从当前机器不存在到指定ip路由),或者是该ip存在,但找不到指定的端
口进行监听。出现该问题,首先检查客户端的ip和port是否写错了,如果正确则从客户端ping一下服务器看是否能ping通,如果能ping通(服务
服务器端把ping禁掉则需要另外的办法),则看在服务器端的监听指定端口的程序是否启动,这个肯定能解决这个问题。
第3个异常是java.net.SocketException: Socket is closed,该异常在客户端和服务器均可能发生。异常的原因是己方主动关闭了连接后(调用了Socket的close方法)再对网络连接进行读写操作。
第
4个异常是java.net.SocketException: (Connection reset或者Connect reset by
peer:Socket write
error)。该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭(或主动关闭或者因为异常退出而
引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect
reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection
reset)。简单的说就是在连接断开后的读和写操作引起的。
第
5个异常是java.net.SocketException: Broken
pipe。该异常在客户端和服务器均有可能发生。在第4个异常的第一种情况中(也就是抛出SocketExcepton:Connect reset
by peer:Socket write
error后),如果再继续写数据则抛出该异常。前两个异常的解决方法是首先确保程序退出前关闭所有的网络连接,其次是要检测对方的关闭连接操作,发现对
方关闭连接后自己也要关闭该连接。
Java之网络编程笔记的更多相关文章
- Netty | 第1章 Java NIO 网络编程《Netty In Action》
目录 前言 1. Java 网络编程 1.1 Javs NIO 基本介绍 1.2 缓冲区 Buffer 1.2 通道 Channel 1.3 选择器 Selector 1.4 NIO 非阻塞网络编程原 ...
- 二十三、Java基础--------网络编程
Java中另一个重要技术就是网络编程了,为了更好的学习web方向的知识,有必要对java之网络编程好好学习,本文将围绕网络编程技术进行分析. 常见的网络协议:UDP.TCP UDP 1. 将数据源和目 ...
- JAVA的网络编程
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
- Java Socket 网络编程心跳设计概念
Java Socket 网络编程心跳设计概念 1.一般是用来判断对方(设备,进程或其它网元)是否正常动行,一 般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于 ...
- 20145325张梓靖 实验五 "JAVA的网络编程"
20145325张梓靖 实验五 "JAVA的网络编程" 实验内容 使用 JVAV语言 进行网络编程 对明文进行加密 设计过程 我完成的是客户端,服务端同伴 20145308刘昊阳 ...
- 【转】JAVA之网络编程
转自:火之光 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者 ...
- JAVA的网络编程【转】
JAVA的网络编程[转] Posted on 2009-12-03 18:04 火之光 阅读(93441) 评论(20) 编辑 收藏 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能, ...
- Java面向对象 网络编程 下
Java面向对象 网络编程 下 知识概要: (1)Tcp 练习 (2)客户端向服务端上传一个图片. (3) 请求登陆 (4)url 需求:上传图片. 客户端: ...
- Java面向对象 网络编程 上
Java面向对象 网络编程 上 知识概要: (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...
随机推荐
- Cortex-M3/4的Hard Fault调试方法
1 Cortex-M3/4的Fault简介 Cortex-M3/4的Fault异常是由于非法的存储器访问(比如访问0地址.写只读存储位置等)和非法的程序行为(比如除以0等)等造成的.常见的4种异常及产 ...
- 利用 NGINX 最大化 Python 性能,第一部分:Web 服务和缓存
[编者按]本文主要介绍 nginx 的主要功能以及如何通过 NGINX 优化 Python 应用性能.本文系国内 ITOM 管理平台 OneAPM 编译呈现. Python 的著名之处在于使用简单方便 ...
- codeforces 459C Pashmak and Buses(模拟,组合数A)
题目 跑个案例看看结果就知道了:8 2 3 题目给的数据是 n,k,d 相当于高中数学题:k个人中选择d个人排成一列,有多少种不同的方案数,列出其中n中就可以了. #include<iostre ...
- KMP高质量代码实现详解
KMP算法 对于KMP算法我分为两个部分说明,第一部分是算法部分,介绍KMP算法的算法思想:第二部分是实现部分,介绍一种厉害的实现代码以及代码注释.当然了由于本文主要介绍怎么实现故而先分析实现,对KM ...
- POJ 2186
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22189 Accepted: 9076 Des ...
- eclipse加速
eclipse老是building workspace及自动更新问题,eclipse加速 最近用Eclipse开发oPhone的一个项目,每次打开Eclipse的时候,总是在build workspa ...
- php curl 分离header和body信息
php中可以通过curl来模拟http请求,同时可以获取http response header和body,当然也设置参数可以只获取其中的某一个.当设置同时获取response header和body ...
- 无线Ad-hoc网络的关键技术之路由(转)
无线Ad-hoc网络的关键技术之路由http://network.51cto.com/art/201003/189719.htm
- Linux信号处理1
函数原型 NAME signal - ANSI C signal handling SYNOPSIS #include <signal.h> typedef void (*sighandl ...
- spring_150803_service
实体类: package com.spring.model; public class DogPet { private int id; private String name; private in ...