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

Java 网络编程

2018-01-27 22:02 127 查看

网络编程一些基本原理

地址:IP地址。每台计算机独特的地址。

端口号: 一台拥有IP地址的主机可以提供许多服务,用端口号来区分与不同的服务交换信息。

同一个协议下(不同协议下可以重复TCP、UDP),端口号不可重复。

端口号为两个字节,0-65535。建议1024以下的端口不要使用。预留给知名厂商。

IP+端口号就能为数据指引方向。

资源定位: URL 统一资源定位符。

协议

TCP:面向连接,就跟打电话,建立连接才会传输,效率相对低下。

UDP:类似发短信,只管往外发,非面向连接,但是效率高,安全性低。

InetAddress 类

封装计算机的ip地址和DNS,没有端口。

静态方法获取对象

InetAddress.getLocalHost()

InetAddress.getByName(“www.163,com”)

InetAddress.getByName(“233.87.1.78”)

方法

getHostAddress() 返回ip地址

gethostName() 返回域名|本机为本机名

package com.bjsxt.net.ip;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
/**
* 没有封装端口
* @author Administrator
*
*/
public class InetDemo01 {

/**
* @param args
* @throws UnknownHostException
* @throws MalformedURLException
*/
public static void main(String[] args) throws UnknownHostException{
//使用getLocalHost方法创建InetAddress对象
InetAddress addr = InetAddress.getLocalHost();
System.out.println(addr.getHostAddress());  //返回:192.168.1.100
System.out.println(addr.getHostName());  //输出计算机名
//根据域名得到InetAddress对象
addr = InetAddress.getByName("www.163.com");
System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
System.out.println(addr.getHostName());  //输出:www.163.com
//根据ip得到InetAddress对象
addr = InetAddress.getByName("61.135.253.15");
System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
System.out.println(addr.getHostName());  //输出ip而不是域名。如果这个IP地 址不存在或DNS服务器不允许进行IP地址和域名的映射,getHostName方法就直接返回这个IP地址。

}

}


InetSocketAddress

显然这个类比上面介绍的InetAddress多了个套接字(socket),这就说明把端口封装进去了。

package com.bjsxt.net.ip;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

/**
* 封装端口:在InetAddress基础上+端口
* @author Administrator
*
*/
public class InetSockeDemo01 {

/**
* @param args
* @throws UnknownHostExcept
15228
ion
*/
public static void main(String[] args) throws UnknownHostException {
InetSocketAddress  address = new InetSocketAddress("127.0.0.1",9999);
address = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),9999);
System.out.println(address.getHostName());
System.out.println(address.getPort());
InetAddress addr =address.getAddress();
System.out.println(addr.getHostAddress());  //返回:地址
System.out.println(addr.getHostName());  //输出计算机名

}

}


URL

URL:统一资源标识符。由四部分组成:协议存放资源的主机域名端口号资源名。如:”http://www.baidu.com:80/index.html?uname=bjsxt

URL是指向互联网“资源”的指针。

package com.bjsxt.net.url;

import java.net.MalformedURLException;
import java.net.URL;

public class URLDemo01 {

/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
//绝对路径构建
URL url = new URL("http://www.baidu.com:80/index.html?uname=bjsxt");
System.out.println("协议:"+url.getProtocol());
System.out.println("域名:"+url.getHost());
System.out.println("端口:"+url.getPort());
System.out.println("资源:"+url.getFile());
System.out.println("相对路径:"+url.getPath());
System.out.println("锚点:"+url.getRef()); //锚点
System.out.println("参数:"+url.getQuery());//?参数 :存在锚点  返回null ,不存在,返回正确

url = new URL("http://www.baidu.com:80/a/");
url = new URL(url,"b.txt"); //相对路径
System.out.println(url.toString());

}

}


简单的网络爬虫原理:爬取百度首页。

package com.bjsxt.net.url;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;

/**
* 获取资源:源代码
* @author Administrator
*
*/
public class URLDemo02 {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.baidu.com"); //主页 默认资源

//获取资源 网络流
/*
InputStream is =url.openStream();
byte[] flush = new byte[1024];
int len =0;
while(-1!=(len=is.read(flush))){
System.out.println(new String(flush,0,len));
}
is.close();
*/

BufferedReader  br =
new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("baidu.html"),"utf-8"));

String msg =null;
while((msg=br.readLine())!=null){
//System.out.println(msg);
bw.append(msg);
bw.newLine();
}
bw.flush();

bw.close();
br.close();

}

}


UDP编程

节本步骤

1.创建客户端的DatagramSocket(用于发送或者接收数据),创建时,定义客户端的监听端口。

2.创建服务器端的DatagramSocket(数据容器(封包)的作用),定义服务器的监听端口。

3.在服务器端定义DAtagramPacket对象,封装发送的数据包。

4.服务器端将数据包发送出去。

5.客户端接受数据包。

package com.bjsxt.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
* 服务端
* 1、创建服务端 +端口
* 2、准备接受容器
* 3、封装成 包
* 4、接受数据
* 5、分析数据
* 6、释放
* @author Administrator
*
*/
public class MyServer {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、创建服务端 +端口
DatagramSocket server = new DatagramSocket(8888);
//2、准备接受容器
byte[] container = new byte[1024];
//3、封装成 包 DatagramPacket(byte[] buf, int length)
DatagramPacket packet =new DatagramPacket(container, container.length) ;
//4、接受数据
server.receive(packet);
//5、分析数据
byte[] data =packet.getData();
int len =packet.getLength();
System.out.println(new String(data,0,len));
//6、释放
server.close();

}

}

package com.bjsxt.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
* 客户端
* 1、创建客户端 +端口
* 2、准备数据
* 3、打包(发送的地点 及端口)
* 4、发送
* 5、释放
*
* 思考: 89.12  数据+类型
* @author Administrator
*
*/
public class MyClient {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、创建客户端 +端口
DatagramSocket client = new DatagramSocket(6666);
//2、准备数据
String msg ="udp编程";
byte[] data =msg.getBytes();
//3、打包(发送的地点 及端口) DatagramPacket(byte[] buf, int length, InetAddress address, int port)
DatagramPacket packet = new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888));
//4、发送
client.send(packet);
//5、释放
client.close();

}

}


那么,发送带类型的参数时候咋办

package com.bjsxt.net.udp;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
* 服务端
* 1、创建服务端 +端口
* 2、准备接受容器
* 3、封装成 包
* 4、接受数据
* 5、分析数据 字节数组-->double
* 6、释放
* @author Administrator
*
*/
public class Server {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、创建服务端 +端口
DatagramSocket server = new DatagramSocket(8888);
//2、准备接受容器
byte[] container = new byte[1024];
//3、封装成 包 DatagramPacket(byte[] buf, int length)
DatagramPacket packet =new DatagramPacket(container, container.length) ;
//4、接受数据
server.receive(packet);
//5、分析数据
double data =convert(packet.getData());
System.out.println(data);
//6、释放
server.close();

}
/**
* 字节数组 +Data 输入流
* @param data
* @return
* @throws IOException
*/
public static double convert(byte[] data) throws IOException{
DataInputStream dis =new DataInputStream(new ByteArrayInputStream(data));
double num =dis.readDouble();
dis.close();
return num;
}
}

package com.bjsxt.net.udp;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
* 客户端
* 1、创建客户端 +端口
* 2、准备数据   double -->字节数组   字节数组输出流
* 3、打包(发送的地点 及端口)
* 4、发送
* 5、释放
*
*
* @author Administrator
*
*/
public class Client {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、创建客户端 +端口
DatagramSocket client = new DatagramSocket(6666);
//2、准备数据
double num =89.12;
byte[] data =convert(num);
//3、打包(发送的地点 及端口) DatagramPacket(byte[] buf, int length, InetAddress address, int port)
DatagramPacket packet = new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888));
//4、发送
client.send(packet);
//5、释放
client.close();

}

/**
* 字节数组 数据源  +Data 输出流
* @param num
* @return
* @throws IOException
*/
public static byte[] convert(double num) throws IOException{
byte[] data =null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos =new DataOutputStream(bos);
dos.writeDouble(num);
dos.flush();

//获取数据
data = bos.toByteArray();
dos.close();
return data;

}
}


TCP编程

服务器端

1.创建服务器,指定端口ServerSocket(int port)

2.接收客户端的连接 阻塞式。

3.发送数据。

4.创建客户端,指定服务器+端口。

5.接受数据。

package com.bjsxt.net.tcp.socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {

public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(8789);

Socket socket=serverSocket.accept();

System.out.println("客户端已经建立连接");
}
}

package com.bjsxt.net.tcp.socket;

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

/**
1、创建客户端   必须指定服务器+端口    此时就在连接
Socket(String host, int port)
2、接收数据 +发送数据
* @author Administrator
*
*/
public class Client {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//1、创建客户端   必须指定服务器+端口    此时就在连接
Socket client = new Socket("localhost",8888);
//2、接收数据
/*
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
String echo =br.readLine(); //阻塞式方法
System.out.println(echo);
*/
DataInputStream dis = new DataInputStream(client.getInputStream());
String echo = dis.readUTF();
System.out.println(echo);
}

}


那么问题来了,多个客户端连接咋办。

package com.bjsxt.net.tcp.socket;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
必须先启动服务器 后连接
1、创建服务器  指定端口   ServerSocket(int port)
2、接收客户端连接
3、发送数据+接收数据

接收多个客户端
*
*/
public class MultiServer {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、创建服务器  指定端口   ServerSocket(int port)
ServerSocket server = new ServerSocket(8888);
//2、接收客户端连接   阻塞式
while(true){ //死循环  一个accept()一个客户端
Socket socket =server.accept();
System.out.println("一个客户端建立连接");
//3、发送数据
String msg ="欢迎使用";
//输出流

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg);
dos.flush();

}

}

}


写个while循环,就能解决问题啦。但是这里有个缺陷。只有给一个客户端发送数据过去之后,才能给下一个客户端发送数据,实际生活中可不允许这样,因此要为每一个连接开辟一个线程。

多线程处理:聊天室原理

先演示给client端用上多线程,这样client就可以一边接,一边发。

package com.bjsxt.net.tcp.chat.demo02;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 创建服务器
* 写出数据:输出流
* 读取数据:输入流
* @author Administrator
*
*/
public class Server {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket server =new ServerSocket(9999);
while(true){
Socket client =server.accept();
//写出数据
//输入流
DataInputStream dis = new DataInputStream(client.getInputStream());
DataOutputStream dos = new DataOutputStream(client.getOutputStream());

while(true){
String msg =dis.readUTF();
System.out.println(msg);
//输出流
dos.writeUTF("服务器-->"+msg);
dos.flush();
}
}

}

}

package com.bjsxt.net.tcp.chat.demo02;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
* 发送数据 线程
* @author Administrator
*
*/
public class Send implements Runnable{
//控制台输入流
private BufferedReader console;
//管道输出流
private DataOutputStream dos;
//控制线程
private boolean isRunning =true;
public Send() {
console =new BufferedReader(new InputStreamReader(System.in));
}
public Send(Socket client){
this();
try {
dos =new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
//e.printStackTrace();
isRunning =false;
CloseUtil.closeAll(dos,console);

}
}
//1、从控制台接收数据
private String getMsgFromConsole(){
try {
return console.readLine();
} catch (IOException e) {
//e.printStackTrace();
}
return "";
}
/**
* 1、从控制台接收数据
* 2、发送数据
*/
public void send(){
String msg = getMsgFromConsole();
try {
if(null!=msg&& !msg.equals("")){
dos.writeUTF(msg);
dos.flush(); //强制刷新
}
} catch (IOException e) {
//e.printStackTrace();
isRunning =false;
CloseUtil.closeAll(dos,console);
}
}

@Override
public void run() {
//线程体
while(isRunning){
send();
}
}

}

package com.bjsxt.net.tcp.chat.demo02;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
* 接收线程
* @author Administrator
*
*/
public class Receive implements Runnable {
//输入流
private  DataInputStream dis ;
//线程标识
private boolean isRunning = true;
public Receive() {
}
public Receive(Socket client){
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
isRunning =false;
CloseUtil.closeAll(dis);
}
}
/**
* 接收数据
* @return
*/
public String  receive(){
String msg ="";
try {
msg=dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
isRunning =false;
CloseUtil.closeAll(dis);
}
return msg;
}
@Override
public void run() {
//线程体
while(isRunning){
System.out.println(receive());
}
}
}

package com.bjsxt.net.tcp.chat.demo02;

import java.io.Closeable;

/**
* 关闭流的方法
* @author Administrator
*
*/
public class CloseUtil {
public static void closeAll(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
}

package com.bjsxt.net.tcp.chat.demo02;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
* 创建客户端: 发送数据+接收数据
* 写出数据:输出流
* 读取数据:输入流
*
输入流 与输出流 在同一个线程内 应该 独立处理,彼此独立

*
*
*
* @author Administrator
*
*/
public class Client {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client = new Socket("localhost",9999);
new Thread(new Send(client)).start(); //一条路径
new Thread(new Receive(client)).start(); //一条路径

}

}


我们解决了客户端收发信息互不干扰,但是还存在一个问题,就是服务器不能同时为多个客户端服务。这就要为每一个客户端的到来,创建一个新的线程

我们在这里只改写server端

package com.bjsxt.net.tcp.chat.demo03;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
* 创建服务器
* 写出数据:输出流
* 读取数据:输入流
* @author Administrator
*
*/
public class Server {
private List<MyChannel> all = new ArrayList<MyChannel>();
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
new Server().start();

}

public void start() throws IOException{
ServerSocket server =new ServerSocket(9999);
while(true){
Socket client =server.accept();
MyChannel channel = new MyChannel(client);
all.add(channel);//统一管理
new Thread(channel).start(); //一条道路
}
}

/**
* 一个客户端 一条道路
* 1、输入流
* 2、输出流
* 3、接收数据
* 4、发送数据
* @author Administrator
*
*/
private class MyChannel implements Runnable{
private DataInputStream dis ;
private DataOutputStream dos ;
private boolean isRunning =true;
public MyChannel(Socket client ) {
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dis,dos);
isRunning =false;
}
}
/**
* 读取数据
* @return
*/
private String receive(){
String msg ="";
try {
msg=dis.readUTF();
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dis);
isRunning =false;
all.remove(this); //移除自身
}
return msg;
}

/**
* 发送数据
*/
private void send(String msg){
if(null==msg ||msg.equals("")){
return ;
}
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dos);
isRunning =false;
all.remove(this); //移除自身
}
}

/**
* 发送给其他客户端
*/
private void sendOthers(){
String msg = this.receive();
//遍历容器
for(MyChannel other:all){
if(other ==this){
continue;
}
//发送其他客户端
other.send(msg);
}
}

@Override
public void run() {
while(isRunning){
sendOthers();
}
}
}

}


下面,来实现私聊功能

package com.bjsxt.net.tcp.chat.demo04;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
* 创建服务器
* 写出数据:输出流
* 读取数据:输入流
* @author Administrator
*
*/
public class Server {
private List<MyChannel> all = new ArrayList<MyChannel>();
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
new Server().start();

}

public void start() throws IOException{
ServerSocket server =new ServerSocket(9999);
while(true){
Socket client =server.accept();
MyChannel channel = new MyChannel(client);
all.add(channel);//统一管理
new Thread(channel).start(); //一条道路
}
}

/**
* 一个客户端 一条道路
* 1、输入流
* 2、输出流
* 3、接收数据
* 4、发送数据
* @author Administrator
*
*/
private class MyChannel implements Runnable{
private DataInputStream dis ;
private DataOutputStream dos ;
private boolean isRunning =true;
private String name;
public MyChannel(Socket client ) {
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
this.name =dis.readUTF();
this.send("欢迎您进入聊天室");
sendOthers(this.name+"进入了聊天室",true);
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dis,dos);
isRunning =false;
}
}
/**
* 读取数据
* @return
*/
private String receive(){
String msg ="";
try {
msg=dis.readUTF();
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dis);
isRunning =false;
all.remove(this); //移除自身
}
return msg;
}

/**
* 发送数据
*/
private void send(String msg){
if(null==msg ||msg.equals("")){
return ;
}
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
CloseUtil.closeAll(dos);
isRunning =false;
all.remove(this); //移除自身
}
}

/**
* 发送给其他客户端
*/
private void sendOthers(String msg,boolean sys){
//是否为私聊 约定
if(msg.startsWith("@")&& msg.indexOf(":")>-1 ){ //私聊
//获取name
String name =msg.substring(1,msg.indexOf(":"));
String content = msg.substring(msg.indexOf(":")+1);
for(MyChannel other:all){
if(other.name.equals(name)){
other.send(this.name+"对您悄悄地说:"+content);
}
}
}else{
//遍历容器
for(MyChannel other:all){
if(other ==this){
continue;
}
if(sys){ //系统信息
other.send("系统信息:"+msg);
}else{
//发送其他客户端
other.send(this.name+"对所有人说:"+msg);
}
}
}
}

@Override
public void run() {
while(isRunning){
sendOthers(receive(),false);
}
}
}

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