网络编程笔记

网络编程
    网络模型
      OSI参考模型(应用层,表示层,会话层,传输层,网络层,数据链路层,物理层)
      TCP/IP参考模型(应用层,传输层,网际层,主机至网络层)
      TCP:Transmission Control Protocol 传输控制协议
      IP:Internet Protocol 互联网协议
    网络通讯要素
      IP地址:网络中设备的标识
      端口号:用于标识进程的逻辑地址,不同进程的标识
  有效端口:0~65535,其中0~1024系统使用或保留端口
      传输协议:通信规则。




      应用层的协议有:HTTP 超文本传输协议 HyperText Transfer Protocol
     FTP  文件传输协议  File Transfer Protocol
     SMTP 简单邮件传输协议
     Telnet 远程登录服务


http://127.0.0.1
http://localhost
127和localhost的映射关系就在本机上。
c:\windows\systems32\drivers\ext\hosts




127.0.0.1,本地回环地址,本机未配置任何IP地址的情况下的地址。
可用于测试本机网卡好坏。DOS——>ping 127.0.0.1


TCP/IP模型中,java网络编程在传输层和网际层,java Web开发在应用层。
每个层都有自己的传输协议。传输层常见的协议有TCP和UDP,网际层最常见的就是IP,
应用层的是HTTP和FTP。


java.net——>InetAddress(用于描述IP的对象)


UDP 
   特点:面向无连接,数据包有限制,速度快
   将数据源和目的封装在数据包中,不需要建立连接。每个数据包的大小限制
   在64K内,可以分多包发。因无连接,是不可靠协议,但速度快。
   UDP传输只需数据源端在即可,接收源端断开没关系。接收端断开时数据包会直
   接丢失。
   例:凌波教学用软件,网络视频会议,桌面共享


TCP
   特点:面向连接.必须先启动服务端再启动客户端。
   建立连接,形成传输数据的通道。在连接中进行大数据量的传输。
   通过三次握手完成连接,是可靠的。必须建立连接,效率稍低。
   单方面断开数据会停止传输。
   通过三次握手可以判断对方是否在线:会建立通路,A首先发送一次数据,B收到后发

   送返回数据,A再发送数据确认。如:A:在? B:我在。 A:恩,知道你在了。




import java.net.*;

class  IPDemo
{
	public static void main(String[] args) throws Exception
	{
		//method_1();//打印本机名和地址
		method_2();//打印指定机器的名和地址
	}

	public static void method_1() throws Exception
	{
		InetAddress i = InetAddress.getLocalHost();//打印本机名和地址

		sop(i.toString());
		sop("Address:"+i.getHostAddress());
		sop("Name:"+i.getHostName());
	}

	public static void method_2() throws Exception
	{
		InetAddress i = InetAddress.getByName("192.168.1.254");
		sop("Address:"+i.getHostAddress());
		sop("Name:"+i.getHostName());
		/*
		打印地址之后打印名字很慢,若IP地址和对应的主机名这个映射关系不在网络上,
		不能够解析成功。打印的名字仍是IP地址。
		*/
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}








网络编程其实就是Socket编程。
Socket(插座)就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是
Socket间的通信,数据在两个Socket间通过IO传输。
类似于两台机器用网线连接,有接口。不同主机上的相同软件之间的连接一样,即Socket。

java.net——>DatagramSocket 此类表示用来发送和接收数据报包的套接字(Socket)。




import java.net.*;

/*
需求:通过UDP传输方式,将一段文字数据发送出去。
定义一个UDP发送端
思路:
	1.建立UDPsocket服务。即建立端点
	2.提供数据,并将数据封装到数据包中。
	3.通过socket服务的发送功能将数据包发送出去。
	4.关闭资源。
*/

class UDPSend 
{
	public static void main(String[] args) throws Exception
	{
		//创建udp服务,通过DatagramSocket对象。
		DatagramSocket ds = new DatagramSocket(7891);


		//确定数据并封装成数据包
		//DatagramPacket(byte[] buf,int length,InetAddress address,int port);
		byte[] buf = "udp data is coming".getBytes();
		
		DatagramPacket dp = new DatagramPacket(buf,buf.length,
			InetAddress.getByName("127.0.0.1"),10000);

		//通过socket服务,用send方法将已有的数据包发送出去
		ds.send(dp);

		//关闭资源
		ds.close();

	}
}

//UDPSend 此代码发送的数据将会丢失,因为面向无连接。


/*
定义UDP的接收端,通常会在定义udpsocket服务时监听一个端口,其实就是给
这个接受网络应用程序定义一个数字标识,方便明确哪些数据过来该应用程序
可以处理。若不定义,系统会给其随机分配一个而造成发送端发送时的端口与
接收端的不匹配而使数据丢失。
需求:定义一个应用程序,用于接收udp协议传输的数据并处理。
思路:
	1.定义UDPsocket服务。
	2.定义一个数据包,因为要存储接收到的字节数据。
		因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
	3.通过socket服务的receive方法将受到的数据存入已定义好的数据包中。
	4.通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
	5.关闭资源

接收端开启后需要接收后才停止,因其有一个阻塞式方法:ds.receive(dp);
*/

class UDPReceive 
{
	public static void main(String[] args) throws Exception
	{
		//创建UDPsocket服务,建立端点
		DatagramSocket ds = new DatagramSocket(10000);//指定10000端口
		/*此句不能放在循环中,下面的语句可以放。
		因此句若放循环会使多个服务用到同一端口而发生BindException异常。
		*/

		
		/*
		//定义数据包,用于存储数据
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf,buf.length);

		//通过服务的receive方法将收到的数据存入数据包中
		ds.receive(dp);

		//通过数据包的方法获取其中的数据,包含地址、端口和数据
		String ip = dp.getAddress().getHostAddress();
		String data = new String(dp.getData(),0,dp.getLength());
		int port = dp.getPort();

		//System.out.println(buf.length);
		System.out.println(ip+"::"+data+"::"+port);
			//port 发送端的数字标识,是系统自动分配的。也可以在发送端指定。

		//关闭资源
		ds.close(); */

		while(true)
		{
			byte[] buf = new byte[1024];
			DatagramPacket dp = new DatagramPacket(buf,buf.length);

			ds.receive(dp);

			String ip = dp.getAddress().getHostAddress();
			String data = new String(dp.getData(),0,dp.getLength());
			int port = dp.getPort();

			System.out.println(ip+"::"+data+"::"+port);
			//ds.close();
		}
	}
}

//需要运行两个控制台。还要先运行接收端再开发送端。






192.168.1.0 :代表一个网络地址段。
192.168.1.255 :代表这个段里面的广播地址。

import java.net.*;
import java.io.*;

class  UdpSend2
{
	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)
		{
			if("over".equals(line))
				break;

			byte[] buf = line.getBytes();

			/*DatagramPacket dp = new DatagramPacket(buf,buf.length,
				InetAddress.getByName("127.0.0.1"),10001);*/
			DatagramPacket dp = new DatagramPacket(buf,buf.length,
				InetAddress.getByName("127.0.0.1"),10001);
			//此包用于将长度为length的包发送到指定主机的指定端口号

			ds.send(dp);
		}
		ds.close();
	}
}


class UdpReceive2
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket(10001);

		while(true)
		{
			byte[] buf = new byte[1024];
			DatagramPacket dp = new DatagramPacket(buf,buf.length);
			//此包用于接受长度为length的数据包

			ds.receive(dp);

			String ip = dp.getAddress().getHostAddress();
			String data = new String(dp.getData(),0,dp.getLength());

			System.out.println(ip+"::"+data);
		}
	}
}






//聊天程序
import java.net.*;
import java.io.*;

/*
编写一个聊天程序,分为收数据和发数据。
这两部分需要同时执行,需要用到多线程技术。
一个线程控制收,另一个控制发。

因为收和发动作是不一致的,所以要定义两个run方法。
而且这两个方法要封装到不同的类中。
*/

class Send implements Runnable
{
	private DatagramSocket ds;
	public Send(DatagramSocket ds)
	{
		this.ds = ds;
	}

	public void run()//覆盖run方法
	{
		try
		{
			BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

			String line = null;

			while((line=bufr.readLine())!=null)
			{
				if("over".equals(line))
					break;

				byte[] buf = line.getBytes();

				DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10002);

				ds.send(dp);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("发送端发送失败!");
		}
	}
}


class Rece implements Runnable
{
	private DatagramSocket ds;
	public Rece(DatagramSocket ds)
	{
		this.ds = ds;
	}
	public void run()
	{
		try
		{
			while(true)
			{
				byte[] buf = new byte[1024];
				DatagramPacket dp = new DatagramPacket(buf,buf.length);

				ds.receive(dp);

				String ip = dp.getAddress().getHostAddress();

				String data = new String(dp.getData(),0,dp.getLength());
					//byte[]  getData();返回数据缓冲区。
					//getLength();返回将要接收到的数据的长度。

				System.out.println(ip+"::"+data);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("接收端接收失败!");
		}
	}
}


class ChatDemo
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket receSocket = new DatagramSocket(10002);
		//发送端端口可由系统分配,但接收端端口需要指定。


		//一定要创建Send和Rece这两个类的对象。
		//因要把Runnable接口的子类对象传给Thread的构造函数。
		new Thread(new Send(sendSocket)).start();
		new Thread(new Rece(receSocket)).start();
	}
}






TCP传输
Socket和ServerSocket
建立客户端和服务端
建立连接后,通过Socket中的IO流进行数据的传输。
关闭Socket。
客户端和服务端应该是两个独立的应用程序。



import java.net.*;
import java.io.*;


/*
Tcp传输。
1.TCP分客户端和服务端。
2.客户端对应的对象是Socket。
  服务端对应的对象是ServerSocket。
*/

/*
客户端
在Socket对象建立时就可以去连接指定主机。
因为Tcp是面向连接的,所以在建立Socket服务时,
就要有服务端存在并连接成功。形成通路后,在该通道进行数据的传输。

需求:给服务端发送一个文本数据。

步骤:
1.创建Socket服务,并制定要连接的主机和端口
*/


class TcpClient//客户端
{
	public static void main(String[] args) throws Exception
	{
		//创建客户端的Socket服务,指定目的的主机和端口
		Socket s = new Socket("127.0.0.1",10003);
		//若此步成功,即通路建立了。通路一建立就会有Socket流(即网络流)。
		//此Socket流中有方法可以拿到输入流或输出流,不需要New。

		//为了发送数据需要获取Socket流中的输出流
		//因为数据可能是任何类型,所以用字节流
		OutputStream out = s.getOutputStream();

		out.write("Tcp is Coming".getBytes());

		s.close();//Socket关闭,流也会被关闭
	}
}


/*
服务端会跟多个客户端进行连接,之所以不会把数据发到不匹配的客户端,
原因是服务端跟SocketA连接后是使用SocketA的流跟其交流,所以不会发错。
Socket用其out向服务端发送,服务端使用A的in接收后用A的out向A发送,A用in接收。


需求:定义端点接收数据并打印在控制台上。

服务端:
  1.建立服务端的Socket服务,ServerSocket();
    并监听一个端口,即打数字标识。
  2.获取连接过来的客户端对象,
    通过ServerSocket的accept方法。此方法是阻塞式的,因没有连接就会等。
  3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到
    该客户端对象的读取流来读取发过来的数据,并打印在控制台上。
  4.关闭服务端。(可选,因还有其他客户端)
*/
class TcpServer
{
	public static void main(String[] args) throws Exception
	{
		//建立服务端Socket服务,并监听一个端口。
		ServerSocket ss = new ServerSocket(10003);

		//通过accept方法获取连接过来的客户端对象。
		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"...connected");

		//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
		InputStream in = s.getInputStream();

		byte[] buf = new byte[1024];
		int len = in.read(buf);

		System.out.println(new String(buf,0,len));

		s.close();//关闭客户端

	}
}







import java.io.*;
import java.net.*;

/*
演示TCP的传输的客户端和服务端的互访。

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/

/*
客户端:
1.建立Socket服务,指定要连接的主机和端口。
2.获取Socket流中的输出流,将数据写到该流中,通过网络发送给服务端。
3.获取Socket流中的输入流,将服务端反馈的数据获取到并打印。
4.关闭客户端资源。
*/


class TcpClient2
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("127.0.0.1",10004);

		OutputStream out = s.getOutputStream();

		out.write("服务端,你好。".getBytes());


		InputStream in = s.getInputStream();

		byte[] buf = new byte[1024];

		int len = in.read(buf);

		System.out.println(new String(buf,0,len));

		s.close();
	}
}

class TcpServer2
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10004);

		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"...connected");

		InputStream in = s.getInputStream();

		byte[] buf = new byte[1024];

		int len = in.read(buf);

		System.out.println(new String(buf,0,len));


		OutputStream out = s.getOutputStream();

		out.write("收到,你也好。".getBytes());

		s.close();
		ss.close();
	}
}







import java.io.*;
import java.net.*;

/*
需求:建立一个文本转换服务器。
客户端给服务器端发送文本,服务端会将文本转换为大写再返回给客户端。
而且客户端可以不断的进行文本转换,当客户端输入over时转换结束。

分析:
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。

源:键盘录入
目的:网络设备,网络输出流
而且操作的是文本数据,可以选择字符流。

步骤:
1.建立服务
2.获取键盘录入
3.将数据发给服务端
4.获取服务端返回的大写数据
5.结束,关闭资源。

都是文本数据,可以使用字符流进行操作,同时提高效率可以加入缓冲区。
*/


class  TransClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("127.0.0.1",10005);

		//定义读取键盘数据的流对象。
		BufferedReader bufr = new BufferedReader
			(new InputStreamReader(System.in));

		//定义目的,将数据写入到Socket输出流,发给服务端。
		BufferedWriter bufOut = new BufferedWriter
			(new OutputStreamWriter(s.getOutputStream()));
		//代替上句:
		//PrintWriter out = new PrintWriter(s.getOutputStream,true);

		//定义一个Socket读取流,读取服务器端返回的大写信息。
		BufferedReader bufIn = new BufferedReader
			(new InputStreamReader(s.getInputStream()));

		String line = null;

		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			/*
			输入over,客户端结束,服务端未判断但也结束了。
			因客户端的s.close();结束时会返回-1,服务端接
			收到-1后便会结束。
			*/

			bufOut.write(line);
			 //发送的数据没有回车符,而服务端在读一行数据
			 //时判断的是回车标记,所以需要加回车符
			bufOut.newLine();
			bufOut.flush();
			//代替上三句:(对应PrintWriter)
			//out.println(line);

			String str = bufIn.readLine();
			System.out.println("server:"+str);
		}

		bufr.close();
		s.close();
	}
}


/*
服务端:
源:Socket读取流。
目的:Socket输出流。
都是文本,装饰。
*/

class TransServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10005);

		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"...connected");

		//读取Socket读取流中的数据
		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));
	
		//目的,Socket输出流。将大写数据写入到Socket输
		//出流,并发送给客户端。
		BufferedWriter bufOut = new BufferedWriter(
			new OutputStreamWriter(s.getOutputStream()));
		//PrintWriter out = new PrintWriter(s.getOutputStream(),true);

		String line = null;
		while((line=bufIn.readLine())!=null)
		{
			System.out.print(line);


			bufOut.write(line.toUpperCase());
			//客户端同样是用的readLine();所以也需要结束标记和刷新
			bufOut.newLine();
			bufOut.flush();
			//out.println(line.toUpperCase());
		}

		s.close();
		ss.close();
	}
}


/*
该例子出现的问题。
现象:客户端和服务端都在莫名的等待。
原因:客户端和服务端都有阻塞式的方法,这些方法没有读到结束标记,那么
就会一直等待而导致两端都等待。
*/







ip               IP             Internet protocol
icmp             ICMP           Internet control message protocol
ggp              GGP            Gateway-gateway protocol
tcp              TCP            Transmission control protocol
egp              EGP            Exterior gateway protocol
pup              PUP            PARC universal packet protocol
udp              UDP            User datagram protocol
hmp              HMP            Host monitoring protocol
xns-idp          XNS-IDP        Xerox NS IDP
rdp              RDP            "reliable datagram" protocol
ipv6             IPv6           Internet protocol IPv6
ipv6-route       IPv6-Route     Routing header for IPv6
ipv6-frag        IPv6-Frag      Fragment header for IPv6
esp              ESP            Encapsulating security payload
ah               AH             Authentication header
ipv6-icmp        IPv6-ICMP      ICMP for IPv6
ipv6-nonxt       IPv6-NoNxt     No next header for IPv6
ipv6-opts        IPv6-Opts      Destination options for IPv6
rvd              RVD            MIT remote virtual disk


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值