网络通信

扫盲 

局域网(LAN,Local Area Network):通过一定形式连接起来的计算机

广域网(WAN,Wide Area Network):LAN延伸到更大范围

因特网:由无数LAN,WAN组成 

IP协议:

  • (Internet Protocol)一种网络协议;
  • Internet网络采用的是TCP/IP协议;
  • 在Internet上存在数以亿计的主机,每台主机在网络上用为其分配的INternet地址代表自己,即IP地址;目前为止,IP地址用4个字节,即32位的二进制数来表示,称为IPv4,为便于使用,通常取每个字节的十进制数,每个字节之间用圆点隔开来表示IP地址,如192.168.1.1
  • TCP/IP模式是一种层次结构,共分为4层,应用层、传输层、互联网层、网络层
  • TCP/IP协议栈中,有两个高级协议,TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)
  • TCP协议:以一种固定连线为基础的协议,提供两台计算机间可靠有序的数据传送,例拨打电话;HTTP、FTP、Telnet等需要使用可靠的通信频道
  • UDP:无连接通信协议,不保证可靠数据的传输,但能向若干个目标发送数据,接收发自若干个源的数据;以地理发送数据包的方式进行;适用于对数据准确性要求不高的场合,如网络聊天室、在线影片等

端口:0 ~ 65535之间的整数;HTTP服务一般使用80端口,FTP服务21端口;0 ~ 1023通常用于一些知名的网络服务和应用

套接字(Socket):用于将应用程序和端口连接起来 

TCP网络程序设计:用Socket类编写通信程序;利用TCP协议进行通信的两个应用程序有主次之分,一个为服务器程序,另一个为客户机程序

InetAddress类:

与IP地址相关类(会报 UnknownHostException 异常)

  • getByName(String host):<InetAddress>获取与Host相对应的InetAddress对象
  • getHostAddress():<String>获取InetAddress对象所包含的IP地址    
  • getHostName():<String>获取此IP地址的主机名    例:MR-PC
  • getLocalHost():<InetAddress>返回本地主机的InetAddress对象    例:192.168.1.92

ServerSocket类 

表示服务器套接字,主要用来等待来自网络上的“请求”,可通过指定端口来等待连接的套接字;服务器套接字一次可以与一个套接字连接,多台客户机同时发出请求会将请求连接的客户机存入队列中,依次取出,建立连接;队列默认大小50,超出连接请求会被拒绝(IOException 异常)

构造方法:

  • ServerSocket():创建非绑定服务器的套接字
  • ServerSocket(int port):创建绑定到特定端口的服务器套接字
  • ServerSocket(int port,int backlog):利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号
  • ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器 

常用方法:

  • accept():<Socket>等待客户机连接,若连接,则创建一套接字;会返回一个和客户端Socket对象相连接的Socket对象;该方法会阻塞线程的执行,知道接收到客户的呼叫
  • isBound():<boolean>判定ServerSocket的绑定状态
  • getInetAddress():<InetAddress>返回此服务器套接字的本地地址
  • isClosed():<boolean>返回服务器套接字的关闭状态
  • close():<void>关闭服务器套接字
  • bind(SocketAddress endpoint):<void>将ServerSocket绑定到特定地址(IP地址和端口号)
  • getInetAddress():<int>返回服务器套接字等待的端口号 

 服务器端的Socket对象使用getOutputStream()方法获得的输出流将指向客户端Socket对象使用getInputStream()获得的那个输入流;同样,服务器端的Socket对象使用geInputStream()获得的输入流将指向客户端Socket对象使用getOutputStream方法获得的输出流

 

TCP网络程序 

单向通信:客户机向服务器发送消息,不要求服务器想客户机发送消息

客户机套接字和服务器套接字连接成功后,客户机通过输出流发送数据,服务器则通过输入流接收数据

服务端关键步骤:

// 第一步:创建服务端套接字
ServerSocket server = new ServerSocket(8998);

// 第二步:等待客户机连接
Socket socket = server.accept();

// 第三步:客户机连接成功,获取客户端信息
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader.readLine()

// 第四步:关闭相关资源
if(reader != null) {
    reader.close();
}
if(socket != null) {
    socket.close();
}

 可直接测试用服务端代码

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

/**
 * TCP服务器端程序
 * @author zl
 *
 */
public class MyTcp {
	
	private BufferedReader reader;
	private ServerSocket server;
	private Socket socket;
	
	void getServer() {
		try {
			server = new ServerSocket(8998);
			System.out.println("服务端套接字创建成功");
			while(true) {
				System.out.println("等待客户机的连接");
				socket = server.accept();
				reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				getClientMessage();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取客户端信息
	 */
	private void getClientMessage() {
		try {
			while(true) {
				System.out.println("客户机:"+reader.readLine());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			if(reader != null) {
				reader.close();
			}
			if(socket != null) {
				socket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		MyTcp tcp = new MyTcp();
		tcp.getServer();
	}

}

 

客户端主要步骤

// 第一步:连接服务端
Socket socket = new Socket("127.0.0.1", 8998);

// 第二步:将客户端信息写入流中
PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);
writer.println(text);

可测试用客户端代码

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

/**
 * 客户端程序
 * 用户在文本框中输入信息发给服务器
 * @author zl
 *
 */
public class MyClien extends JFrame {

	private PrintWriter writer;
	Socket socket;
	private JTextArea ta = new JTextArea();
	private JTextField tf = new JTextField();
	Container cc;
	
	public MyClien(String title) {
		super(title);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		cc = this.getContentPane();
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBorder(new BevelBorder(BevelBorder.RAISED));
		getContentPane().add(scrollPane, BorderLayout.CENTER);
		scrollPane.setViewportView(ta);
		cc.add(tf, "South");
		tf.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				writer.println(tf.getText());
				ta.append(tf.getText()+'\n');
				ta.setSelectionEnd(ta.getText().length());
				tf.setText("");
			}
		});
	}
	
	public void connect() {
		ta.append("尝试连接\n");
		try {
			socket = new Socket("127.0.0.1", 8998);
			writer = new PrintWriter(socket.getOutputStream(),true);
			ta.append("完成连接\n");
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		MyClien clien = new MyClien("向服务器送数据");
		clien.setSize(200,200);
		clien.setVisible(true);
		clien.connect();
	}
	
}

                       

        

 

UDP 

用户数据报协议(udp):网络信息传输的另一种形式;比TCP:更快,不可靠

DatagramPacket:表示数据包

DatagramSocket:表示发送和接收数据包的套接字

 

模式:

  • 将数据打包(数据包),然后将数据包发往目的地
  • 接收别人发来的数据包,然后查看数据包

使用步骤:

发送

  1. 使用DatagramSocket()创建一个数据报套接字
  2. 使用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 创建要发送的数据包 《四个参数:数据包的内存空间和大小,数据包的目标地址和端口》;在发送时必须指定接收方Socket地址和端口号
  3. 使用 DatagramSocket类的send()方法发送数据包

接收

  1. 使用DatagramSocket(int port) 创建数据包套接字,绑定到指定的端口;在接收程序的时候,必须指定一个端口号
  2. 使用DatagramPacket(byte[] buf, int length)创建字节数组来接收数据包《两个参数:数据包的内存空间和大小》
  3. 使用DatagramPacket类的receive()接收UDP包,在没有可接收的数据时,会阻塞,等到数据传来

示例:广播数据报程序

主机不断地重复播出节目预报,保证加入到同一组的主机随时可以接收到广播信息。接受者将正在接收的信息放在一个文本域中,并将接收的全部信息放在另一个文本域中

地址范围:224.0.0.0~224.255.255.255

主机代码

主要代码:

// 一、创建一个数据包套接字
MulticastSocket socket = new MulticastSocket(9898);

// 二、创建要发送的数据包
InetAddress iaddress = InetAddress.getByName("224.255.1.0");
byte data[] = weather.getBytes(); // 声明字节数组
DatagramPacket packet = new DatagramPacket(data, data.length,iaddress,port);	

// 三、发送数据
socket.send(packet);		
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;

public class Weather extends Thread{

	String weather = "节目预报:八点有大型晚会,请收听";
	int port = 9898;
	InetAddress iaddress = null;
	MulticastSocket socket = null;// 声明多点广播套接字
	
	// 构造方法
	Weather() {
		try {
			iaddress = InetAddress.getByName("224.255.1.0");
			socket = new MulticastSocket(port);
			socket.setTimeToLive(1);// 指定发送范围是本地网络
			socket.joinGroup(iaddress); // 加入广播组
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public void run() {
		while(true) {
			DatagramPacket packet = null;
			byte data[] = weather.getBytes(); // 声明字节数组
			// 将数据打包
			packet = new DatagramPacket(data, data.length,iaddress,port);
			System.out.println(new String(data));
			
			try {
                                // 发送数据
				socket.send(packet);
				sleep(3000);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		Weather w = new Weather();
		w.start();
	}
	
}

接收广播程序

主要代码

// 第一步:绑定多点广播套接字
MulticastSocket socket = new MulticastSocket(9898);

// 第二步:接收数据包
InetAddress group = InetAddress.getByName("224.255.1.0");
byte data[] = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length,group,9898);

// 第三步:接收UDP包
socket.receive(packet);
String message = new String(packet.getData(),0,packet.getLength());

 

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;

public class Receive extends JFrame implements Runnable,ActionListener{

	int port;
	InetAddress group = null;
	MulticastSocket socket = null;  // 创建多点广播套接字对象
	JButton ince = new JButton("开始接收");
	JButton stop = new JButton("停止接收");
	JTextArea inceAr = new JTextArea(10,10); // 接收广播的文本域
	JTextArea inced = new JTextArea(10,10);
	Thread thread;
	boolean b = false;
	
	public Receive() {
		super("广播数据报");
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		thread = new Thread(this);
		ince.addActionListener(this);  // 绑定单击事件
		stop.addActionListener(this);
		inceAr.setForeground(Color.blue);
		JPanel north = new JPanel();
		north.add(ince);
		north.add(stop);
		add(north,BorderLayout.NORTH);
		JPanel center = new JPanel();
		center.setLayout(new GridLayout(1, 2));
		center.add(inceAr);
		center.add(inced);
		add(center,BorderLayout.CENTER);  // 设置面板布局
		validate();   // 刷新
		port = 9898;
		try {
                        // 指定接收地址
			group = InetAddress.getByName("224.255.1.0");
                        // 绑定多点广播套接字
			socket = new MulticastSocket(port);
                        // 加入广播组
			socket.joinGroup(group);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		setBounds(100,50,360,380);
		setVisible(true);
	}
	
	// 单击事件
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == ince) {
			ince.setBackground(Color.RED);
			stop.setBackground(Color.yellow);
			if(!(thread.isAlive())) {
				thread = new Thread(this);
			}
			thread.start();
			b = false;
		}
		
		if(e.getSource() == stop) {
			ince.setBackground(Color.yellow);
			stop.setBackground(Color.red);
			b = true;
		}
	}
	
	public static void main(String[] args) {
		Receive rec = new Receive();
		rec.setSize(460,200);
	}

	@Override
	public void run() {
		while(true) {
			byte data[] = new byte[1024];
			DatagramPacket packet = null;
                        // 待接收的数据包
			packet = new DatagramPacket(data, data.length,group,port);
			try {
                                // 接收数据包
				socket.receive(packet);
                                // 获取数据包中内容
				String message = new String(packet.getData(),0,packet.getLength());
				inceAr.setText("正在接收的内容:\n"+message);
				inced.append(message+"\n");
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(b == true) {
				break;
			}
		}
	}

}

      

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值