黑马程序员---网络编程(socket编程)

一、网络模型

OSI参考模型和TCP/IP参考模型,如下图:
网络编程开发处于传输层与网络层。

二、通信协议三要素

IP地址、端口、网络协议

1.IP地址:

它是网络中的设备标识;
不易记忆,可用主机名标识,存在映射关系;
本机回环地址为:127.0.0.1,主机名为:localhost。

InetAddress类:其中IP地址与java相关的类为InetAddress类。InetAddress类无构造函数,可以通过静态方法getLocalHost()方法获取本机的InetAddress对象。

常用方法如下:

static InetAddress getByName(String host)  
//获取指定主机的IP和主机名。(最好用ip地址去获取,主机名需要解析)  
static InetAddress[] getAllByName(String host)  
//在给定主机名的情况下,根据系统上配置的名称服务返回IP地址所组成的数组。返回对象不唯一时,用此方法。  
String getHostAddress()  
//返回IP地址字符串文本形式,以IP地址为主。  
String getHostName()  
//返回IP地址主机名。

练习这些常用方法:

package com.itheima;  
/* 
 * 练习使用InetAddress类的一些常用方法: 
 * 包括static修饰的类方法 InetAddress.getLocalHost(),InetAddress.getByName(String host),InetAddress.getAllbyName(String host) 
 * 以及对象方法getHostAddress(),getHostName()。 
 */  
import java.net.*;  
public class InetAddressPractice {  
    public static void main(String[] args)throws Exception {  
        //获取本机的InetAddress对象  
        InetAddress myInetAdd = InetAddress.getLocalHost();  
        //获取本机的IP地址(字符串形式)和主机名  
        String myIPAddress = myInetAdd.getHostAddress();  
        String myHostName = myInetAdd.getHostName();  
        System.out.println("my host ip is "+myIPAddress+",Name is "+myHostName);  
        //获取给定指定Ip地址的主机的InetAddress对象  
        InetAddress givenInetAdd = InetAddress.getByName("221.236.31.210");  
        System.out.println("given host Name is "+ givenInetAdd.getHostName());  
        //获取给定指定域名的主机的InetAddress对象  
        InetAddress givenInetAddName[] = InetAddress.getAllByName("www.baidu.com");  
        for(InetAddress inet : givenInetAddName){  
            System.out.println("given host ip is "+ inet.getHostAddress());  
        }  
    }  
}  
2.端口号:

用于标识进程的逻辑地址;
有效端口:0~65536,系统使用或保留的端口是0~1024。

3.网络协议:
通信规则,包含TCP和UDP协议。
4.Socket对象:

JAVA与网络编程最基础的对象。

a、它被称为插座,是网络服务提供的一种机制;
b、通信两端都要有Socket,才能建立服务;
c、网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。

三、UDP编程

概念:

是面向无连接,明确对方的接口,速度快,是不可靠的网络协议。常用于视频会议,聊天等场所。

特点:

a、面向无连接,即将数据及源和目的封装成数据包中,不建立链接的发送
b、每个数据包的大小限制在64K之内
c、因无连接,是不可靠的协议
d、不建立连接,速度快。

步骤:

        1)发送数据:
     
a、建立UDPSocket服务,在此无需指定端口,也可以将端口加入。如果不指定的话,系统会随机分配一个端口,如第一次运行时端口为1093,那么第二次就会顺延为1094,再运行会一直顺延,因为之前的端口还没有得到释放,所以会顺延端口号值。
b、提供数据,并将数据封装到数据包中
c、通过socket服务的发送功能,将数据包发送出去
d、关闭资源

        2)接收数据:

a、定义UDPSocket服务。通常会监听一个端口,其实就是给这个接收网路应用程序定义数字标识,方便于明确哪些数据过来该应用程序可以处理。
b、定义一个数据包,用来存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
c、通过socket服务的receive方法接收到的数据存入已定义好的数据包中
d、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
e、关闭资源


       在定义接收数据的方法中,仍会在DatagramSocket构造函数中传入DatagramPacket的参数,这是因为收到的数据太多,需要解析,通过将数据封装成对象,易于解析,所以需要传入参数。

注意:

        1、发送端与接收端是两个独立的运行程序。
        2、在发送端,要在数据包对象中明确目的地IP及端口。
        3、在接收端,要指定监听的端口。

发送端:
package com.itheima;  
/* 
 * 设置一个通过UDP传输协议的发送端,并发送一段数据 
 */  
import java.net.*;  
public class MySendProgramUDP {  
  
    public static void main(String[] args)throws Exception {  
        //创建数据报套接字对象  
        DatagramSocket sendSocket = new DatagramSocket();  
        //创建数据包对象  
        byte datebyte[] = "this is send content".getBytes();  
        DatagramPacket dataPacket = new DatagramPacket(datebyte,datebyte.length,InetAddress.getByName("127.0.0.1"),3002);  
        //发送数据  
        sendSocket.send(dataPacket);  
        sendSocket.close();  
    }  
} 
接收端:
/* 
 * 接收一段通过UDP协议发送的数据 
 */  
import java.net.*;  
public class MyReceiveProgramUDP {  
  
    public static void main(String[] args)throws Exception {  
        while(true){  
        //创建一个DatagramSocket对象  
        DatagramSocket receiveSocket = new DatagramSocket(3002);  
        //创建一个接收数据的数据包对象  
        byte bytes[] = new byte[1024];  
        DatagramPacket receivePacket = new DatagramPacket(bytes,bytes.length);  
        receiveSocket.receive(receivePacket);  
        System.out.println("content is:"+new String(receivePacket.getData(),0,receivePacket.getLength()));  
        receiveSocket.close();  
        }  
    }  
}

练习:

package com.itheima;
/**
 * 开发一个即时聊天小程序
 */
import java.net.*;
import java.io.*;
class Send implements Runnable{
	private DatagramSocket ds ;
	public Send(DatagramSocket ds){
		this.ds = ds;
	}
	public void run(){
		BufferedReader in = null;
		DatagramPacket dp = null;
		try{
			in = new BufferedReader(new InputStreamReader(System.in));
			String str = null;
			while((str=in.readLine())!=null){
				dp = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getByName("192.168.103.23"),10000);
				ds.send(dp);
				if(str.equals("886"))
					break;
			}}catch(IOException e){e.printStackTrace();}
		finally{
			if(in!=null)
				try {
					in.close();
				} catch (IOException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			if(ds!=null)
				ds.close();
		}
	}
}
class Receive implements Runnable{
	private DatagramSocket ds;
	public Receive(DatagramSocket ds){
		this.ds = ds;
	}
	public void run(){
		byte bs[] = new byte[1024];
		DatagramPacket dp = new DatagramPacket(bs,bs.length);
		try{
			while(true){
				ds.receive(dp);
				String str = new String(dp.getData(),0,dp.getLength());
				System.out.println(str);
				if(str.equals("886"))
					break;
			}}catch(IOException e){}
			finally{
				if(ds !=null)
					ds.close();
			}
	}
}
public class Chat{
	public static void main(String[] args){
		try {
			new Thread(new Send(new DatagramSocket())).start();
			new Thread(new Receive(new DatagramSocket(10000))).start();
		} catch (SocketException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
}

四、TCP协议

概念:

面向连接的,必须连接成功才能传输数据。常用于的场景比如下载等

特点:

a、面向连接,在建立连接后,形成传输数据的通道
b、在连接中进行大数据量的传输
c、通过三次握手完成连接,是可靠的协议
d、必须建立连接,效率稍慢

三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次确认连接成功。

步骤:

客户端:

        通过查阅Socket对象的API文档,发现在该对象在建立时,就可去连接指定主机,因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,再通过该通道进行数据的传输。
         1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取
         2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,还需要获取Socket的输入流
         3)通过输出流的write()方法将要发送的数据写入到流中
         4)关闭Socket流资源

服务端:

        服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。需监听一个端口。
         1)建立服务端的Socket服务,并监听一个端口。通过ServerSocet带端口参数的构造函数
         2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会一直等待
         3)客户端如果发过来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并输出到指定目的地。
         4)关闭服务端(可选)。一般服务端是常开的,因为在实际应用中,随时有客户端在请求连接和服务。但这里需要定时关闭客户端对象流,避免某一个客户端长时间占用服务器端。

服务器端:
package com.itheima;
//ServerSocket类.accept方法获取Socket对象,使用Socket的方法获取输出流和输入流进行编程
import java.net.*;
import java.io.*;
public class MyServer{
	public static void main(String[] args)throws IOException{
		ServerSocket ss = new ServerSocket(10001);
		Socket socket = ss.accept();
		OutputStream out = socket.getOutputStream();
		out.write("hello World by TCP transmission".getBytes());
		out.close();
	}
}
客户机端:
package com.itheima;
import java.net.*;
import java.io.*;		
public class MyClient {
	public static void main(String[] args)throws IOException{
		Socket socket = new Socket("192.168.103.45",10001);
		InputStream in = socket.getInputStream();
		byte bs[] = new byte[1024];
		int len;
		while((len = in.read(bs))!=-1){
			System.out.print(new String(bs,0,len));
		}
		System.out.println();
		socket.close();
	}
}

练习:
package com.itheima;
/*
 * 传输图片的服务器端
 */
import java.net.*;
import java.io.*;
public class PhotographServer {
	public static void main(String[] args)throws IOException {
		InputStream in;
		ServerSocket ss = new ServerSocket(10003);
		Socket socket = ss.accept();
		in = new FileInputStream("a.jpg");
		OutputStream out = socket.getOutputStream();
		byte bs[] = new byte[1024];
		int len;
		while((len = in.read(bs))!=-1){
			out.write(bs,0,len);
		}
		in.close();
		ss.close();
	}
}
package com.itheima;
/*
 * 传输图片的客户机端
 */
import java.net.*;
import java.io.*;
public class PhotographClient {
	public static void main(String[] args)throws IOException{
		Socket socket = new Socket("192.168.103.45",10003);
		InputStream  in = socket.getInputStream();
		OutputStream out = new FileOutputStream("b.jpg");
		byte bs[] = new byte[1024];
		int len;
		while((len = in.read(bs))!=-1){
			out.write(bs,0,len);
		}
		out.close();
		socket.close();
	}
}



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值