一、网络通讯要素
①找到对方IP
②端口:数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以要给这些网络应用程序都用数字进行标识,为了方便称呼这个数字,叫做端口(逻辑端口)
下图主要看本地端口
web服务:80 tomat:8080 mySql:3306
③定义通信规律,这个通讯规则称为协议。
国际组织定义了通讯协议:TCP\IP
二、IP地址:InetAddress对象
IP地址:
网络中设备的标识、
不易记忆,可用主机名
本地回环地址:127.0.0.1主机名:localhost
InetAddress ia=InetAddress.getLocalHost();//返回本地地址
System.out.println(ia.toString());//返回地址字符串+主机名
System.out.println(ia.getHostAddress());//获取此IP地址字符串
System.out.println(ia.getHostName());//获取此IP地址的主机名
InetAddress i=InetAddress.getByName("www.baidu.com");//给主机名返回IP地址
System.out.println(i.getHostAddress());
三、端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0-65535,其中0-1024系统使用或保留端口
四、传输协议特点
UDP特点:
①将数据及源和目的封装成数据包中,不需要建立连接
②每个数据报的大小在限定的64k内
③因无连接,是不可靠的协议
④不需要建立连接,速度快
应用:聊天工具(QQ)、网络视频会议、桌面共享
TCP特点:
①建立连接,形成传输数据的通道
②在连接中进行大数据量传输(不用封包)
③通过三次握手完成连接,是可靠协议
④必须建立连接,效率低
应用:下载
五、网络编程Socket
就是为网络服务提供 的一种机制
通讯的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
①UDP
DatagramSocket:此类表示用来发送和接收数据报 的套接字
因为要封装成包,而包又比较复杂,所以将此包封装承对象DatagramPacket
在方法中只要参数带InetAddress就是发送端的,该地址是目的地址。
需求:通过udp传输方式,将一段文字发送出去(发送端)
思路:
1,建立udpsocket服务
2,提供数据,并将数据封装承包
3,通过socket服务的发送功能,将数据包发送出去
4,关闭资源
public static void main(String[] args)throws Exception {
//1,创建udp服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket();
//2,确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[]buf="udp hahah".getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10000);
//3,通过socket服务,将已有的数据发送出去,通过send方法
ds.send(dp);
//关闭资源
ds.close();
}
需求:定义一个应用程序,用于接收udp协议传输的数据并处理(接收端)
思路:
1,定义udpsocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义一个数字表示,方便哪个应用程序进行处理
2,定义一个数据包,因为要存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息
3,通过socket服务的receive方法将接收的数据存入已经定义好的数据包中
4,通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
5,关闭资源
import java.net.*;
public class udpReceive {
public static void main(String[] args)throws Exception {
System.out.println("接收端开启***********************");
//1,创建udp socket,建立端点
DatagramSocket ds=new DatagramSocket(10000);
//2,定义数据包,用于存储数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//3,通过服务的receive方法接收数据存入数据包中
ds.receive(dp);//阻塞式方式
//4,通过数据包的方法获取其中的数据
InetAddress ia=dp.getAddress();//获取IP地址
String ip=ia.getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println(ip+"---"+data+"---"+port);
//5,关闭资源
ds.close();
}
}
//Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
//接收端监听端口,这个端口不能是已经被其他应用程序占用的,否则会抛出此异常↑
//注意以上两个应用程序,第一个是发送端,第二个是接收端,因为是无连接形式,所以在eclipse中要先开启接收端
需求:发送端通过键盘键入,输入一行就发送给接收端,接收端一直开启while(true)
public class send {
public static void main(String[] args)throws Exception {
DatagramSocket ds=new DatagramSocket();
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufr.readLine())!=null)//也不会造成死循环,因为readline中也调用read()方法,
//该方法是阻塞方法,键盘没输入就等待
{
if("886".equals(line))
break;
byte[] buf=line.getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10001);
ds.send(dp);
}
ds.close();
}
}
public class receive {
public static void main(String[] args)throws Exception {
DatagramSocket ds=new DatagramSocket(10001);
while(true) //不会造成死循环,因为receive是阻塞式方法,若发送方不发送数据,则阻塞在该处
{
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);
InetAddress ia=dp.getAddress();
String ip=ia.getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":::"+data);
//将关闭去掉,只要发送端想连,就发,就能接收
}
}
}
编写一个聊天程序,有收数据的部分,和发数据的部分,这两部分需要同时执行。那就需要用到多线程技术。
一个线程控制收,一个线程控制发。因为收和发动作不一致,所以要定义两个run方法,相应的应该定义在两个类中
//发送端
import java.io.*;
import java.net.*;
public class send implements Runnable{
private DatagramSocket ds;
send(DatagramSocket ds){
this.ds=ds;
}
public void run() {
BufferedReader bufr=new BufferedReader(new InputStreamReader( System.in));
String line=null;
try {
while((line=bufr.readLine())!=null) {
if("886".equals(line))
break;
byte[] buf=line.getBytes();
DatagramPacket dp=new DatagramPacket(buf,0,buf.length,InetAddress.getByName("192.168.1.255"),10003);
ds.send(dp);
}
bufr.close();
} catch (IOException e) {
throw new RuntimeException("读取失败");
}
}
}
//接收端
import java.io.*;
import java.net.*;
public class rece implements Runnable {
DatagramSocket ds;
rece(DatagramSocket ds){
this.ds=ds;
}
public void run() {
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
try {
while(true) {
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+data);
}
} catch (IOException e) {
throw new RuntimeException("无法获取");
}
}
}
//主方法
import java.net.*;
public class demo {
public static void main(String[] args)throws Exception {
DatagramSocket ds1=new DatagramSocket();
DatagramSocket ds2=new DatagramSocket(10003);
new Thread(new send(ds1)).start();
new Thread(new rece(ds2)).start();
}
}