Java Socket网络编程

网络编程:OSI参考模型   TCP/IP参考模型

网络通讯要素:IP地址  端口号  传输协议

IP地址:网络中设备的标识,不易记忆,可用主机名,本机回环地址127.0.0.1,主机名:localhost

端口号:用于标识进程的逻辑地址,不同进程的标识,有效端口0~65535,其中0~1024系统使用或保留端口

传输协议:通讯的规则,常见协议有TCP  UDP


InetAddress类:

//获取本机ip对象

InetAddress ip = InetAddress.getLocalHost();

//获取主机名称

System.out.println(ip.getHostName());

//获取主机地址

System.out.println(ip.getHostAddress());

//将指定的字符串主机地址获取其ip对象

InetAddress ip1 = InetAddress.getByName("192.122.1.123");

InetAddress.getByName//获取该对象的所有IP地址


UDP协议:

将数据及源和目的封装成数据包中,不需要建立连接,每个数据包的大小在限制在64K内,因无连接,是不可靠协议,不需要建立连接,速度快


TCP协议

建立连接,形成传输数据的通道,在连接中进行大量数据传输,通过三次握手完成连接,是可靠协议,必须建立连接,效率会稍低。


Socket:就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间是通过IO传输


例1,需求:将数据通过udp协议发送出去。

步骤:

1,建立udpsocket服务。DatagramSocket 对象。

2,将数据封装成数据包。

3,通过socket服务的send方法将数据包发送出去。

4,关闭服务。

代码:

//创建udpsocket服务。

DatagramSocket ds = new DatagramSocket(8888); 

byte[] buf = "hi,ge men  坐着 UDP 来了".getBytes(); 

//将数据封装成数据包。

DatagramPacket dp =  
	new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.249"),10000);

//使用socket服务的send方法。将数据发出。

ds.send(dp);

//关闭服务。

ds.close();


例2,需求:建立udpsocket服务,监听一个10000端口,接收数据,并打印到屏幕上。

步骤:

1,建立接收端的socket服务。通常需要监听一个端口。其实就是分配了具体指定的数据标识。

2,通过服务的receive方法接收数据,并将数据存储到数据包中。

3,通过数据包对象的方法,获取具体的数据内容。

4,将数据内容打印。

5,关闭服务.

代码:

//通过该服务接收10000端口来数据。首先要建立一个数据包,用来存储接收到的数据。
DatagramSocket ds = new DatagramSocket(10000);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);//将数据存储到数据包中。该方法是阻塞式方法。
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+port+"..."+text);
//关闭服务。
ds.close();


例3,一个聊天程序

import java.awt.*;
import java.awt.event.*;
import java.net.*;

public class Chat {
	Frame f = new Frame("我的聊天室");
	// 定义一个主框架

	TextField tfIP = new TextField(15);
	// 定义一个输入文本框,指定文本框中最多显示的字符个数为15

	List lst = new List(10);
	// 定义一个图形化的列表框,表明最多显示10行,多的用滚动条显示

	DatagramSocket ds;//数据报套接字是包投递服务的发送或接收点。
	//此程序是在一台电脑上,所以可以只定义一个数据报套接字,接、收都用它


	/*
	 * 由于DatagramSocket的构造函数声明可能抛出异常,我们的程序需要用try…catch语句
	 * 进行异常捕获处理,所以不能直接在这里调用DatagramSocket的构造函数对ds进行初始化,
	 * 我们需要将ds的初始化放在Chat类的构造函数中去完成。
	 */

	public Chat() {//构造方法中生成线程,并充当数据接受端
		try {
			ds = new DatagramSocket(3000);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		//接受方应该在一个单独的线程中运行,一面在接受不到进行阻塞时
		//不影响其他程序的运行
		new Thread(new Runnable() {//用匿名内部类来实现
			public void run() {
				byte buf[] = new byte[1024];//构造存放接受内容的数据包的缓冲数组
				DatagramPacket dp = new DatagramPacket(buf, 1024);
				while (true) {
					try {
						ds.receive(dp);
				//接受网络发送过来的消息,并把接受到的消息放在dp数据包中
						lst.add(dp.getAddress().getHostAddress()+":"+dp.getPort()+
							": "+new String(buf, 0, dp.getLength()), 0);
						//用列表框的add方法把接受到的内容显示出来,第二个参数为0表示把
						//最后添加的显示在第一行这样聊天时新的内容才在最上面,不用拖动
						//滚动条来显示
						//显示时把发送方的ip地址和端口字符串形式先显示,后面显示内容
					} catch (Exception e) {
						if(!ds.isClosed()){
							e.printStackTrace();
					//我们在关闭窗口时关闭了数据报套接字,而recevie还在等待,就会有异常
						}
					}
				}
			}
		}).start();
	}

	public static void main(String[] args) {
		Chat chat = new Chat();
		chat.init();
	}

	// 初始窗口
	public void init() {
		f.setSize(302, 300);// 设置窗口宽度为300,高度为300
		f.add(lst);// 主框架中添加列表框

		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add("West", tfIP);// 把文本框添加到面板上的左边

		TextField tfData = new TextField(20);
		p.add("East", tfData);// 添加一个可以显示20个字符的文本框放在面板的右边
		f.add("South", p);    // 把面板添加到主框架的下方
		f.setVisible(true);   // 让主框架可视
		f.setResizable(false);// 让重设窗口大小为false,限制用户改变窗口的大小

		// 增加关闭窗口的事件处理代码
		f.addWindowListener(new WindowAdapter() {
			// 用匿名内部类的方式在主框架上添加一个事件处理器
			// 重写关闭方法,让程序退出时释放端口等资源
			public void windowClosing(WindowEvent e) {
				ds.close(); // 程序退出时,关闭Socket,释放相关资源
				f.setVisible(false);
				f.dispose();
				System.exit(0);
			}
		});

		// 下面增加在消息文本框中按下回车键的事件处理代码
		tfData.addActionListener(new ActionListener() {
			// 重写actinonPerformed方法,所在组件发生操作时调用,这里处理回车事件
			public void actionPerformed(ActionEvent e) {
				// 取出文本框中的消息字符串,并将其转换成字节数组				
				byte[] buf;
				
				//buf=tfData.getText().getBytes();
				//如果用此句,tfData变量就必须是final常量
				
				buf = e.getActionCommand().getBytes(); 
				//getActionCommand返回与此动作相关的命令字符串。
				try {
					DatagramPacket dp = new DatagramPacket(buf, buf.length,
							InetAddress.getByName(tfIP.getText()), 3000);
				// 新建数据包,通过文本框tfIP文本区域内容得到IP,并转换成为InetAddress类型
					// 设定接受端接受该数据包的端口为3000

					ds.send(dp); // 发送数据包
				} catch (Exception ex) {
					ex.printStackTrace();
				}
				/*
				 * 上面的Exception的引用变量名不能为e,而是改写成了ex,因为e已经在
				 * actionPerformed方法中作为形式参数变量名被定义过了。
				 */
				((TextField) e.getSource()).setText("");
			}
		});
	}
}


TCP网络程序:

客户端对Socket,服务端对象ServerSocket

建立客户端和服务器端,

建立连接后,通过Socket中的IO流进行数据的传输

关闭socket


例2,需求:建立一个客户端,给服务端发送一些文字信息。 

步骤:

一,建立客户端:

1,创建客户端的socket服务,通常可以在建立客户端对象时,指定服务端的地址和端口。

如果没有指定,可以通过方法,connect进行指定目的的连接。

2,获取socket流中的输出流对象,给服务端写点数据

3,关闭资源

二,建立服务端:

1,建立服务端socket服务。ServerSocket 给服务端加上一个数字标识,分配一个端口号。

让该程序监听一个端口。

2,获取连接过来的客户端对象。使用获取到的客户端和客户端进行通信。

3,关闭客户端。

4,关闭服务端。

客户端代码:

Socket s = new Socket("192.168.1.249",10002);

//如果连接建立成功,就有了socket流。

//获取socket输出流,将数据写到服务端去。

OutputStream out = s.getOutputStream();

out.write("hi,哥们 骑着 TCP 来了".getBytes());

s.close();


服务端代码:

//建立服务端socket服务,并监听一个端口。

ServerSocket ss = new ServerSocket(10002);

//获取客户端对象。

Socket s = ss.accept();//是阻塞式方法。

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

String ip = s.getInetAddress().getHostAddress();

String text = new String(buf,0,len);

System.out.println(ip+":"+text);

s.close();

ss.close();
 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值