java语言网络编程

一:必要的基本知识
网络:将不同区域的计算机连接到一起
ip地址: 确定计算机在网络上的一个绝对地址(可以看作是一个房子)
端口号:区分计算机软件(可以看作是房子里的房间)
资源定位符:url(可以定位到计算机中某个文件的位置,可以相成是房间里的东西)
数据的传输:1.tcp 类似于三次握手 面向连接,安全可靠,效率低
                     2.udp 短信,非面向连接,效率高,安全性低

二:掌握两个类  
                         可以将其理解成io中的File类,找到计算机的地址
类一: InetAddress(封装计算机的ip地址和dns,没有端口)   dns是域名解析
代码如下:
package jibenlei;

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

//InetAddress中的构造方法不支持外部访问,所以我们利用静态方法来获取对象
//这个类可以得到对象的静态方法有三种,基本方法有两个

public class Inetaddress {

	public static void main(String[] args) throws UnknownHostException {
		//通过静态方法得到该类的对象
   //  InetAddress a=InetAddress.getLocalHost();  //得到指向本机的对象
	//	InetAddress a=InetAddress.getByName("www.163.com");  //通过域名得到指向该地址的对象
		InetAddress a=InetAddress.getByName("124.132.144.132");  //通过ip地址得到指向该地址的对象
     
     System.out.println("ip地址为"+a.getHostAddress());
     System.out.println("域名为"+a.getHostName());
	}

}

类二:InetSocketAddress (在上个类的基础上又封装了端口)
代码如下:
package jibenlei;

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

//这个类可以调用构造方法
public class InetsocketAddress {

	public static void main(String[] args) throws UnknownHostException {
		//构造InetSocketAddress对象  直接通过域名加端口
		InetSocketAddress a=new InetSocketAddress("www.163.com",8888);
        System.out.println(a.getHostName());
		System.out.println(a.getPort());
		System.out.println(a.getAddress());
		//构造对象,通过InetAddress对象加端口
		InetAddress b=InetAddress.getByName("www.163.com");
		InetSocketAddress c=new InetSocketAddress(b,8888);
		System.out.println(c.getHostName());
		System.out.println(c.getPort());
		System.out.println(c.getAddress());
	}

}

三:url详解
url通常用于唯一的标识一个资源。由四部分组成:协议,存放资源的主机域名,资源文件名和端口号。资源可以是简单的文件或目录,亦可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

我们应该学习java类库中的URL,URL还可以选择指定一个端口,它是用来建立到远程主机tcp连接的端口号,如果未指定该端口号,则使用协议默认的端口
http://www.baidu.com:80/MosaicDocs-old/url-primer.html

URL:  1.创建   URL(String str)通过绝对路径创建

                      URL(URL context,String str) 通过相对路径创建

          代码如下:

package jibenlei;

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

public class url {

	public static void main(String[] args) throws MalformedURLException {
	//绝对路径构造	
	 URL url=new URL("http://www.baidu.com:80/index.html#aa?uname=bjsxt");
	 //#aa表示锚点  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());
	 
	 url=new URL(url,"b.txt");  //相对路径构造
	 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());
	}

}
获取网络资源:代码如下
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;



public class url {
//我们来获取资源:源代码
	//URL中有一个方法  openStream()打开到此url的连接并返回一个用于从该链接读入的InputStream
	public static void main(String[] args) throws IOException {
	//绝对路径构造	
	 URL url=new URL("http://www.baidu.com"); //主页 默认资源
	 
/*	 InputStream is=url.openStream();
	 byte b[]=new byte[1024];
	 int len=is.read(b);
	 while(len!=-1) {
		 System.out.println(new String(b,0,len));
	 }
	 is.close();
	*/ 
	 //有的时候会出现乱码,出现的原因可能是数组字节数不够,另一个是编码和解码的字符集不统一,我们可以使用转换流来
	 //转换解码的字符集,所以我们写了以下代码
	 
	 BufferedReader br=new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
	
	 String msg=null;
			 while((msg=br.readLine())!=null) {
				 System.out.print(msg);
			
			 }
			 
	 br.close();
	 
	 
	}

}


四:udp通信 
建立一个服务器端:

package jibenlei;

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

public class Myserver {
	//udp编程  以数据为中心,不安全,非面向链接,效率高  java中的udp类是 DatagramSocket 和DatagramPacket
	/*
	 * 一:客户端  1.创建客户端:DatagramSocket 类
	 * 2.准备数据 字节数组
	 * 3.打包 DatagramPacket +服务器地址+端口
	 * 4.发送   5.释放资源
	 * 
	 * 二:服务器端: 1.创建服务器 DatagramSocket 类+指定端口
	 * 2.准备接受容器 字节数组 封装 DatagramPacket
	 * 3.包 接受数据  4.分析  5.释放数据
	 */
	public static void main(String[] args) throws IOException {
		DatagramSocket server=new DatagramSocket(8888);  //创建服务器+端口
		byte container[]=new byte[1024];  //准备接受容器
		DatagramPacket packet=new DatagramPacket(container,container.length);// 2.准备接受容器 字节数组 封装 DatagramPacket
        server.receive(packet);  //包 接受数据
        byte data[]=packet.getData();  //分析数据
        int len=packet.getLength();
        System.out.println(new String(data,0,len));
        server.close();  //释放资源
	}
	

}

建立一个客户端:

package jibenlei;

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

public class Myclient {

	public static void main(String[] args) throws IOException {
		DatagramSocket client=new DatagramSocket(6666);  //创建客户端+端口
        String msg="Hello World";  //准备数据
        byte data[]=msg.getBytes();
        DatagramPacket packet=new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888));
        //打包数据
        client.send(packet);  //发送包
        client.close();  //释放资源
	}

}

以上我们是将字符串进行输出,然后我们将解决输出任意数据+类型

package jibenlei;

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

public class Myserver {
	//udp编程  以数据为中心,不安全,非面向链接,效率高  java中的udp类是 DatagramSocket 和DatagramPacket
	/*
	 * 一:客户端  1.创建客户端:DatagramSocket 类
	 * 2.准备数据 字节数组
	 * 3.打包 DatagramPacket +服务器地址+端口
	 * 4.发送   5.释放资源
	 * 
	 * 二:服务器端: 1.创建服务器 DatagramSocket 类+指定端口
	 * 2.准备接受容器 字节数组 封装 DatagramPacket
	 * 3.包 接受数据  4.分析  5.释放数据
	 */
	public static void main(String[] args) throws IOException {
		DatagramSocket server=new DatagramSocket(8888);  //创建服务器+端口
		byte container[]=new byte[1024];  //准备接受容器
		DatagramPacket packet=new DatagramPacket(container,container.length);// 2.准备接受容器 字节数组 封装 DatagramPacket
        server.receive(packet);  //包 接受数据
        byte data[]=packet.getData();  //分析数据  将字节数组变成double
        double a=convert(packet.getData());
        System.out.println(a);
        server.close();  //释放资源
	}
	
	public static double convert(byte data[]) throws IOException {
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(data));
		double num=dis.readDouble();
		dis.close();
		return num;
	}

}
package jibenlei;

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

public class Myclient {
//将double类型变成字符数组,用convert方法
	public static void main(String[] args) throws IOException {
		DatagramSocket client=new DatagramSocket(6666);  //创建客户端+端口
        Double num=48.23; //准备数据
        byte data[]=convert(89.12);
        DatagramPacket packet=new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888));
        //打包数据
        client.send(packet);  //发送包
        client.close();  //释放资源
	}

	
	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;
	}
}

client server 模型   一般用于局域网
browser(浏览器) server 模型  一般用于互联网,方便,一般电脑上都有安装

Tcp:
tcp中的服务器端:
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class server03 {
//现在服务器是等客户端发一条信息,它读一条。但是正常的聊天室中服务器的读取和客户端发不发信息无关
	public static void main(String[] args) throws IOException {
	//1.创建服务器  指定端口
	ServerSocket server=new ServerSocket(8888);
	//2.接收客户端连接  阻塞式
	
		
	Socket client=server.accept();
	//写出数据  先读取后输出
	 //读取数据
	 DataInputStream dis=new DataInputStream(client.getInputStream());
	 String msg=dis.readUTF();
	 System.out.println(msg);
	 
	 //输出数据
	 DataOutputStream dos=new DataOutputStream(client.getOutputStream());
	 dos.writeUTF("服务器-->"+msg);
	 dos.flush();
}
}


tcp中的客户端:
import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket;
public class client03 {      //这个时候客户端有明确的顺序,即先输出数据后读取数据,这样跟日常的聊天软件不符,因为输入流和输出流在同一个线程内,应该放在不同的线程中  public static void main(String[] args) throws IOException {   //1.创建客户端时,必须指定服务器端+端口  此时就在连接 (客户端的端口是系统内部分配)    Socket client=new Socket("localhost",8888);     //控制台输入流  我们从控制台上获取数据    BufferedReader console=new BufferedReader(new InputStreamReader(System.in));    String info=console.readLine();               //输出数据    DataOutputStream dos=new DataOutputStream(client.getOutputStream());    dos.writeUTF(info);    dos.flush();         //读取数据    DataInputStream dis=new DataInputStream(client.getInputStream());    String msg=dis.readUTF();    System.out.println(msg);  }
}
这个时候我们的聊天室还有很多问题,比如服务器仅能跟一个客服端连接,客户端仅能发送一次信息
我们在客户端中加入多线程,在服务器端中加入多线程并加入容器管理多线程。

服务器

import java.awt.List;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AllPermission;
import java.util.ArrayList;

public class server04 {
//为每个客户端建立一个管道,彼此访问服务器时没有先后顺序(服务器中加入线程)
//为了实现群聊,我们在跟客户端建立连接时应该知道还有没有别人,所以增加容器管理
	
	private ArrayList<kehu> all=new ArrayList<kehu>();
	public static void main(String[] args) throws IOException {
		new server04().start();
		
	    
	    
	}

	public void start() throws IOException {
		ServerSocket server=new ServerSocket(9999);
		 while(true) {
			    Socket client=server.accept();
			    kehu a=new kehu(client);
			    all.add(a);         //我们使用容器对线程(客户端和服务器的通道)进行管理     
			    new Thread(a).start();  //一条道路
			    
			    }
	}
	
	class kehu implements Runnable{
	    private DataInputStream dis;
	    private DataOutputStream dos;
	 
	    
	    public kehu(Socket client) throws IOException {
	    	dis=new DataInputStream(client.getInputStream());
	    	dos=new DataOutputStream(client.getOutputStream());
	    
	    }
		
	    private String receive() throws IOException {   //读取数据
	    	String msg=dis.readUTF();
	    	return msg;
	    }
	    
	    private void send(String msg) throws IOException {
	    	if(msg==null&&msg.equals("")) {
	    		return;
	    	}
	    	dos.writeUTF(msg);
	    	dos.flush();
	    }
	    
	    private void sendothers() throws IOException {
	    	String msg=receive();
	    	//遍历容器
	    	for(kehu other:all) {
	    	 if(other==this) {  //如果遍历的是本身,跳过
	    		 continue;
	    	 }
	    	 //发送给其他客户端
	    	 other.send(msg);
	    	}
	    }
	    
		public void run() {
			while(true) {
				try {
					//send(receive());  //这是服务器接收客户端a的信息又返回客户端a,并没有实现发给其他人
					sendothers();  //将客户端a发来的信息发给其他的客户端
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			
		}

	}

}

客户端

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

public class client04 {

	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();
	}

}

客户端里的输入输出线程:
输入线程
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class receive implements Runnable{
	private DataInputStream dis;     //输入流
   
    public receive(Socket client) throws IOException {
    	dis=new DataInputStream(client.getInputStream());  //初始化输入流,这个时候需要客户端跟服务器建立的socket,这样才知道从哪输入的
    }
	

    public String receive() throws IOException {  //我们读取数据
    	String msg=dis.readUTF();
    	return msg;
    }

	public void run() {
		
		try {
			while(true) {
			String str=receive();
			System.out.println(str);}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

输出线程:

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

public class send implements Runnable{
    private BufferedReader console;  //一种输入流是从控制台输入,一种输出流
    private DataOutputStream dos;
    
    send(){
    	console=new BufferedReader(new InputStreamReader(System.in));
    }
    
    send(Socket client) throws IOException{
    	this();
    	dos=new DataOutputStream(client.getOutputStream());
    }
	
	private String get() throws IOException {    //从控制台上得到数据
		return console.readLine();
	}
	
	private void send() throws IOException {  //将得到的数据输出
		String msg=get();
		if(msg!=null) {
			dos.writeUTF(msg);
			dos.flush();
		}
	}
	public void run() {
		try {
			while(true) {
			send();}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

我们通过多线程完成了群聊的功能,然后解决私聊的问题。
服务器端:
import java.awt.List;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AllPermission;
import java.util.ArrayList;

public class server04 {
//为每个客户端建立一个管道,彼此访问服务器时没有先后顺序(服务器中加入线程)
//为了实现群聊,我们在跟客户端建立连接时应该知道还有没有别人,所以增加容器管理
	
	private ArrayList<kehu> all=new ArrayList<kehu>();
	public static void main(String[] args) throws IOException {
		new server04().start();
		
	    
	    
	}

	public void start() throws IOException {
		ServerSocket server=new ServerSocket(9999);
		 while(true) {
			    Socket client=server.accept();
			    kehu a=new kehu(client);
			    all.add(a);         //我们使用容器对线程(客户端和服务器的通道)进行管理     
			    new Thread(a).start();  //一条道路
			    
			    }
	}
	
	class kehu implements Runnable{
	    private DataInputStream dis;
	    private DataOutputStream dos;
	    private String name;
	 
	    
	    public kehu(Socket client) throws IOException {
	    	dis=new DataInputStream(client.getInputStream());
	    	dos=new DataOutputStream(client.getOutputStream());
	        this.name=dis.readUTF();
	        this.send("欢迎进入聊天室");
	        this.sendothers(this.name+"进入了聊天室",true);
	    }
		
	    private String receive() throws IOException {   //读取数据
	    	String msg="";
	    	msg=dis.readUTF();
	    	return msg;
	    }
	    
	    private void send(String msg) throws IOException {
	    	if(msg==null&&msg.equals("")) {
	    		return;
	    	}
	    	dos.writeUTF(msg);
	    	dos.flush();
	    }
	    
	    private void sendothers(String msg,boolean iftrue) throws IOException {
	        //查看是否为私聊还是群聊
	    	if(msg.startsWith("@")&&msg.indexOf(":")>-1) {//私聊
	    		//获取name
	    		String name=msg.substring(1,msg.indexOf(":"));
	    		String content=msg.substring(msg.indexOf(":")+1);   //左闭右开所以我们要+1
	    		for(kehu other:all) {
	    			if(other.name.equals(name)) {
	    				other.send("对您悄悄的说"+content);
	    			}
	    		}
	    		
	    	}
	    	else {
	    	
	    	//遍历容器
	    	for(kehu other:all) {
	    	 if(other==this) {  //如果遍历的是本身,跳过
	    		 continue;
	    	 }
	    	 //发送给其他客户端
	    	 if(iftrue==true) {
	    	 other.send("系统信息"+msg);
	    	 }
	    	 else {
	    		 other.send(this.name+"对所有人说"+msg);}
	    	} }
	    }
	    
		public void run() {
			while(true) {
				try {
					//send(receive());  //这是服务器接收客户端a的信息又返回客户端a,并没有实现发给其他人
					sendothers(receive(),false);  //将客户端a发来的信息发给其他的客户端
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			
		}

	}

}

客户端:

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

public class client04 {

	public static void main(String[] args) throws UnknownHostException, IOException {
		 System.out.println("请输入姓名");
		 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		 String name=br.readLine();
		 if(name==null) {
			 return;
		 }
		 
		 Socket client=new Socket("localhost",9999);
		
         new Thread(new send(client,name)).start();
         new Thread(new receive(client)).start();
	}

}
客户端的输出流:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class send implements Runnable{
    private BufferedReader console;  //一种输入流是从控制台输入,一种输出流
    private DataOutputStream dos;
    String name;
    
    send(){
    	console=new BufferedReader(new InputStreamReader(System.in));
    }
    
    send(Socket client,String name) throws IOException{
    	this();
    	dos=new DataOutputStream(client.getOutputStream());
    	this.name=name;
    	send(this.name);
    }
	
	private String get() throws IOException {    //从控制台上得到数据
		return console.readLine();
	}
	
	private void send(String msg) throws IOException {  //将得到的数据输出
		
		if(msg!=null) {
			dos.writeUTF(msg);
			dos.flush();
		}
	}
	public void run() {
		try {
			while(true) {
			send(get());}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

客户端的输入:
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class receive implements Runnable{
	private DataInputStream dis;     //输入流
   
    public receive(Socket client) throws IOException {
    	dis=new DataInputStream(client.getInputStream());  //初始化输入流,这个时候需要客户端跟服务器建立的socket,这样才知道从哪输入的
    }
	

    public String receive() throws IOException {  //我们读取数据
    	String msg=dis.readUTF();
    	return msg;
    }

	public void run() {
		
		try {
			while(true) {
			String str=receive();
			System.out.println(str);}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值