您的位置:首页 > 理论基础 > 计算机网络

Java基础学习笔记之网络编程

2018-02-21 21:57 766 查看

Java基础之网络编程

1.网络编程概述

什么是网络编程

指的是在多个设备(计算机)执行,其中的设备使用一个网络中的所有连接到对方编写程序


网络编程的目的

与其他计算机进行通信


网络编程的问题

1.如何确定网络上的一台或多台主机
2.主机与服务器间如何进行数据传输


2.网络基础

1).OSI参考模型

分别为:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
模型过于理想化,未能在因特网上进行广泛推广


2).TCP/IP参考模型

分别为:应用层,传输层,网络层,物理+数据链路层


3)IP和端口号

IP: IP用于在网络上唯一确定一台主机

端口号:每个进程都有一个唯一的端口号,不同的进程有不同的端口号,端口号被规定为一个16位的整数 0~65535。其中,0~1023被预先定义的服务通信占用(如MySql占用端口3306,http占用端口80等)。

端口号与IP地址的组合得出一个网络套接字。

3.InetAddress类

1)InetAddress

Java中通过InetAddress类表示IP地址,用于实现主机名与IP地址之间的转换。InetAddress类描述了32位和128位的IP地址,并通过他的两个子类Inet4Address和Inet6Address来实现


2)InetAddress的基本使用

创建InetAddress实例

由于InetAddress的构造方法被私有化了,所以不能通过其构造方法来创建实例,只能通过其静态方法来创建其实例对象。

public static InetAddress getByName(String host) 确定主机名称的IP地址获取InetAddress实例对象

public static InetAddress getLocalHost() 获得本地主机的InetAddress对象

public static InetAddress getByAddress(byte[] addr)给定原始IP的情况下,返回InetAddress对象


常用方法

String getHostAddress() 返回IP地址字符串

String getHostName() 获得此IP地址的主机名


例子:

/**
* getByName(String host) 确定主机名称的IP地址。
* getHostName() 获取此IP地址的主机名。
* getHostAddress() 返回文本显示中的IP地址字符串。
* getLocalHost() 返回本地主机的地址。
* @throws Exception
*/
@Test
public void test0() throws Exception {
InetAddress i1 = InetAddress.getLocalHost();
Sy
4000
stem.out.println(i1);

InetAddress i2 = InetAddress.getByName("DESKTOP-V7RHDD3");
System.out.println(i2.getHostName() + ":" + i2.getHostAddress());

}


结果:

DESKTOP-V7RHDD3/192.168.43.68
DESKTOP-V7RHDD3:192.168.43.68


4.网络通信协议

网络通信协议

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


通信协议分层的思想

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


传输层协议中有两个非常重要的协议:

传输控制协议TCP(Transmission Control Protocol)
用户数据报协议UDP(User Datagram Protocol)


TCP与UDP的不同点

TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低

UDP协议:
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
因无需连接,故是不可靠的
发送数据结束时无需释放资源,速度快


5.Socket

1)Socket基本介绍:

网络通信其实就是Socket间的通信。
Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
一般主动发起通信的应用程序属客户端,等待通信请求的为服务端


2)Socket的构造方法

Socket(String host,int port) 向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。

Socket(InetAddress address,int port) 根据InetAddress对象所表示的IP地址以及端口号port发起连接。


3)Socket常用方法

InetAddress getLocalAddress() 返回对方Socket中的IP的InetAddress对象

int getLocalPort() 返回本地Socket中的端口号

InetAddress getInetAddress() 返回对方Socket中IP地址

int getPort() 返回对方Socket中的端口号

void close() 关闭Socket,不可在以后的网络连接中使用,除非创建新的套接字

InputStream getInputStream() 获取与Socket相关联的字节输入流,用于从Socket中读数据。

OutputStream getOutputStream() 获取与Socket相关联的字节输出流,用于向Socket中写数据。

Socket accept() 等待客户端的连接请求,返回与该客户端进行通信用的Socket对象

void setSoTimeout(int timeout) 设置accept()方法等待连接的时间为timeout毫秒。若时间已到,还没有客户端连接,则抛出InterruptedIOException异常,accept()方法不再阻塞,该倾听Socket可继续使用。若timeout值为0,则表示accept()永远等待。该方法必须在倾听Socket创建后,在accept()之前调用才有效。

void close() 关闭监听Socket

InetAddress getInetAddress() 返回此服务器套接字的本地地址

int getLocalPort() 返回此套接字在其上监听的端口号

SocketAddress getLocalSocketAddress() 返回此套接字绑定的端点的地址

shutdownInput() 关闭输入流。

shutdownOutput() 关闭输出流。


4)Socket通信

套接字(Socket)是TCP/IP协议的编程接口,一个Socket由一个IP地址,和一个端口号唯一确定。


使用Socket进行通信的基本步骤

客户端:

1.创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。

2.打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输

3.按照一定的协议对 Socket  进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。

4.关闭 Socket:断开客户端到服务器的连接,释放线路


服务端:

1.调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。

2.调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。

3.调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。

4.关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。


例子1:

客户端与服务器通信

/**
* 客户端
*/
@Test
public void client() {
Socket s = null;
InputStream is = null;
OutputStream os = null;
try {
s = new Socket(InetAddress.getByName("127.0.0.1"), 6666);
// 写出数据
os = s.getOutputStream();
os.write("这边是客户端...".getBytes());
os.flush();
s.shutdownOutput();
is = s.getInputStream();
// 读取用户连接数据
byte[] buf = new byte[1024];
int len = 0;

while ((len = is.read(buf)) != -1) {
System.out.print(s.getInetAddress().getHostAddress() + ":");
System.out.print(new String(buf, 0, len) + "\n");
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (s != null) {
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/**
* 服务端
*/
@Test
public void server() {
ServerSocket ss = null;
Socket s = null;
InputStream is = null;
OutputStream os = null;
try {
System.out.println("等待连接...");
ss = new ServerSocket(6666);
s = ss.accept();
System.out.println("连接成功...");
is = s.getInputStream();
// 读取用户连接数据
byte[] buf = new byte[1024];
int len = 0;

while ((len = is.read(buf)) != -1) {
System.out.print(s.getInetAddress().getHostAddress() + ":");
System.out.print(new String(buf, 0, len) + "\n");
}

// 返回数据
os = s.getOutputStream();
os.write("服务器已收到".getBytes());
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (s != null) {
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}


结果:

Client:
127.0.0.1:服务器已收到

Server:
等待连接...
连接成功...
127.0.0.1:这边是客户端...


例子2:

传输文件练习

客户端传输文件给服务端,服务端保存到本地,并返回发送成功信息给客户端

@Test
public void Client() {
Socket socket = null;
FileInputStream fis = null;
OutputStream os = null;
InputStream is = null;
try {
//创建socket链接
socket = new Socket(InetAddress.getByName("127.0.0.1"), 6666);
//创建输出流
os = socket.getOutputStream();
fis = new FileInputStream(new File("1.txt"));//输入流用来读取传输文件
//读取文件并写出
byte[] buff = new byte[1024];
int len = 0;
while((len = fis.read(buff)) != -1) {
os.write(buff,0,len);//写出文件
}
socket.shutdownOutput();

//读取返回信息
is = socket.getInputStream();
while((len = is.read(buff)) != -1) {
String str = new String(buff,0,len);
System.out.println(
1604d
str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭连接
if(is != null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(os != null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

@Test
public void server() {

ServerSocket ss = null;
Socket socket = null;
OutputStream os = null;
InputStream is = null;
FileOutputStream fos = null;
try {
//创建socket服务器
ss = new ServerSocket(6666);
//等待连接
socket = ss.accept();
os = socket.getOutputStream();
is = socket.getInputStream();
fos = new FileOutputStream(new File("2.txt"));
//将读取的文件写出
byte[] buff = new byte[1024];
int len = 0;
while((len = is.read(buff)) != -1) {
fos.write(buff, 0, len);
}
//打印成功信息
System.out.println("接受完成:" + socket.getInetAddress().getHostName() + ":" + socket.getInetAddress().getHostAddress());
//返回成功信息
os.write("接受成功".getBytes());
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭连接
if(os != null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
if(is != null) {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

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

}

}
}


例子3

简易多线程聊天室

实现思路:

客户端的实现:

首先每个客户端只需要连接一次服务器
客户端可以进行连续的读写


服务端的实现

服务端可以同时接受多个客户端的连接
服务端可以进行连续的读写


提取两者的相同点,都可以同时进行连续的读写操作:

创建读操作线程,处理读数据功能
创建写操作线程,处理写数据功能


对于服务器来说需要接受多个用户的连接:

所以创建一个服务器处理线程用来处理不同的链接用户


WriteHandler类

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.Scanner;
/**
* 处理写数据
* @author lenovo
*
*/
public class WriteHandler implements Runnable {
private OutputStream os = null;
private Socket socket = null;

public WriteHandler(OutputStream os, Socket socket) {
this.os = os;
this.socket = socket;
Thread t = new Thread(this);
t.start();
}

public void run() {
while (true) {
Scanner input = new Scanner(System.in);
String str = input.next();
try {
os.write((this.socket.getInetAddress().getHostName() + ": " + new Date().toString() + "\n" + str)
.getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


ReadHandler 类

import java.io.IOException;
import java.io.InputStream;

/**
* 读取数据
* @author lenovo
*
*/
public class ReadHandler implements Runnable {
private InputStream is = null;

public ReadHandler(InputStream is) {
this.is = is;
Thread t = new Thread(this);
t.start();
}

public void run() {
byte[] buf = new byte[1024];
int len = 0;
try {
while (true) {
while ((len = this.is.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}


ServerHandler类

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 处理服务器连接
* @author lenovo
*
*/
public class ServerHandler implements Runnable {
private Socket s = null;

public ServerHandler(Socket s) {
this.s = s;
Thread t = new Thread(this);
t.start();
}

public void run() {
try {
System.out.println(this.s.getInetAddress().getHostName() + ": 已连接");//打印连接信息
ReadHandler read = new ReadHandler(this.s.getInputStream());//开启读数据线程
WriteHandler write = new WriteHandler(this.s.getOutputStream(), s);//开启写数据线程
} catch (IOException e) {
e.printStackTrace();
}
}

}


Server类

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
* @author lenovo
*
*/
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);
while(true) {
Socket s = ss.accept();
ServerHandler sh = new ServerHandler(s);
}
}
}


Client 类

import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
/**
* 客户端
* @author lenovo
*
*/
public class Client {
public static void main(String[] args) throws Exception{
Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 6666);//创建连接
ReadHandler read = new ReadHandler(s.getInputStream());//开启读线程
WriteHandler write = new WriteHandler(s.getOutputStream(), s);//开启写线程

CountDownLatch countDownLatch = new CountDownLatch(10);
countDownLatch.await();//等待所有子线程执行完
}
}


结果:

客户端1发送:
这里是客户端1
服务器收到了吗

客户端2发送:
这里是客户端2
服务器收到了吗

服务器:
127.0.0.1: 已连接
127.0.0.1: 已连接
127.0.0.1: Tue Mar 13 22:43:34 CST 2018
这里是客户端1
127.0.0.1: Tue Mar 13 22:43:41 CST 2018
服务器收到了吗
127.0.0.1: Tue Mar 13 22:43:49 CST 2018
这里是客户端2
127.0.0.1: Tue Mar 13 22:43:53 CST 2018
服务器收到了吗


6.UDP网络编程

1)UDP

类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。

UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接


例子:

@Test
public void Client() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
DatagramPacket dp = new DatagramPacket("这是客户端".getBytes(), 0, "这是客户端".getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
ds.send(dp);//发送数据
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
ds.close();
}
}

@Test
public void Server() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(6666);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);//接收数据
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(data);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
ds.close();
}
}


结果:

接收端server:

这是客户端


7.URL

1)URL

统一资源定位符,它表示 Internet 上某一资源的地址。通过 URL 我们可以访问 Internet 上的各种网络资源。

2)URL常见协议

http,ftp,file


3)URL常用构造函数

URL(String url) 通过一个表示URL地址的字符串可以构造一个URL对象。

URL(String protocol, String host, String file) 从指定的 protocol名称, host名称和 file名称创建一个URL。

URL(String protocol, String host, int port, String file) 创建 URL从指定对象 protocol(协议,如http) , host , port数,和 file 。


3)URL常用方法

public String getProtocol(  )     获取该URL的协议名
public String getHost(  )           获取该URL的主机名
public String getPort(  )            获取该URL的端口号
public String getPath(  )           获取该URL的文件路径
public String getFile(  )             获取该URL的文件名
public String getRef(  )             获取该URL在文件中的相对位置
public String getQuery(   )        获取该URL的查询名


例子:

@Test
public void url() throws Exception {
URL url = new URL("http://www.baidu.com");
System.out.println(url.getProtocol());
System.out.println(url.getHost());
}


结果:

http
www.baidu.com


例子2:

public void test1() throws Exception {
URL url = new URL("http://www.baidu.com");
System.out.println(url.getContent());//获取此URL的内容。
System.out.println(url.getFile());

InputStream is = url.openStream();//打开与此 URL ,并返回一个 InputStream ,以便从该连接读取
byte[] buf = new byte[1024];
int len = 0;
String str = "";
while((len = is.read(buf)) != -1) {
str += new String(buf, 0, len, "utf-8");
}
System.out.println(str);//打印网页内容
is.close();
}


结果:

sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@7dc5e7b4

<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=??度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>  <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号  <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>


7.URLConnection

URL的方法 openStream():

能从网络上读取数据若希望输出数据,例如向服务器端的 CGI (公共网关接口-Common Gateway Interface-的简称,是用户浏览器和服务器端的应用程序进行连接的接口),程序发送一些数据,则必须先与URL建立连接,然后才能对其进行读写,此时需要使用 URLConnection 。

URLConnection:

表示到URL所引用的远程对象的连接。当与一个URL建立连接时,首先要在一个 URL 对象上通过方法 openConnection() 生成对应的 URLConnection 对象。

如果连接过程失败,将产生IOException.

URL netchinaren = new URL ("http://www.baidu.com/index.shtml");
URLConnectonn u = netchinaren.openConnection( );


URLConnection类

通过URLConnection对象获取的输入流和输出流,即可以与现有的CGI程序进行交互。

public Object getContent( ) throws IOException
public int getContentLength( )
public String getContentType( )
public long getDate( )
public long getLastModified( )
public InputStream getInputStream( )throws IOException
public OutputSteram getOutputStream( )throws IOException




参考自尚硅谷教学文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: