-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
第一讲. 概述
网络通信要素:IP(本地回环地址 127.0.0.1 ,主机名localhost), 端口(0~65535), 协议
网络层次:OSI参考模型,7层参考模型;TCP/IP的参考模型:应用层(如 http),传输层(如 TCP),网际层(如 IP),主机至网络层
两大传输协议:
UDP(好比:步话机) | TCP(好比:打电话) |
|
|
- Java中的ip对象 InetAddress,单例设计模式,通过getLocalHosh(),getByAddress(),getByName()等方法获得实例对象
- socket 套接字 ,Java靠Socket完成网络的传输层通信,即收发数据包。
第二讲. DatagramSocket :UDP的Socket
- *.*.*.255是广播地址,*.*.*.0代表一个网络段
- 由于端口可能还未释放,反复运行发送程序系统会自动顺延端口号,当然也可以指定发送端口
- 定义udp接受端时,需要监听某一个端口,其实就是给这个接收网络应用程序定义一个数字标识
- 重复new Socket会发生BindExcepiton 重复绑定异常
import java.net.*;
import java.io.*;
class UDPSend
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true){
String line = in.readLine();//阻塞式方法
if("886".equals(line))
break;
byte[] data = line.getBytes();
//构造方法为:DatagramPacket(byte[] buf, int length, InetAddress address, int port)
DatagramPacket dp = new DatagramPacket
(data,data.length,InetAddress.getByName("59.66.201.255"),50000);//广播地址
ds.send(dp);
}
in.close();
ds.close();//端口可能还未释放,反复运行发送程序系统会自动顺延端口号
}
}
class UDPReceive
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(50000);
while(true){
//DatagramSocket ds = new DatagramSocket(50000); // BindException重复绑定异常
byte[] buff = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff,buff.length);
ds.receive(dp);//阻塞式的方法
String ip = dp.getAddress().getHostAddress();
String data =new String(dp.getData(),0,dp.getLength());
System.out.println("ip::"+ip+"\tdata::"+data);
System.out.println(dp.getPort());
}
//ds.close();
}
}
第三讲. Scoket,ServerSocket :TCP的套接字对象
- Socket:在建立时就可以连接主机,因为TCP是面向连接的
- ServerSocket:服务端,建立是要绑定端口,通过accept阻塞式方法接收客户端socket对象
- 现象:客户端和服务端都在莫名的等待。 原因:两端的阻塞式方法未读到结束标志。
/*从客服端的键盘录入文本数据。服务器接收到数据,转化为大写并转发回客户端。客户端将其打印到控制台上*/
import java.io.*;
import java.net.*;
class TcpClient
{
public static void main(String[] args) throws Exception
{
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String line;
while(!((line=input.readLine()).equals("over")))
{
Socket socket = new Socket("127.0.0.1",50000);
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);//这里必须autoflush
out.println(line);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String data = in.readLine();
System.out.println("从服务端转发来的大写数据:"+data);
socket.close();
}
}
}
class TcpServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(50000);
while(true){
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println("ip::"+ip);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String data = (in.readLine()).toUpperCase();
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println(data);
s.close(); //在服务器端必须关闭Socket以断开客服端连接
}
}
}
练习:复制文本文件,Socket中shutdownOutputStream()方法的应用:写入结束符。
import java.io.*;
import java.net.*;
class TextClient
{
public static void main(String[] args) throws Exception
{
BufferedReader in = new BufferedReader(new FileReader("TCPDemo.java"));
Socket s = new Socket("127.0.0.1",50000);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line;
while((line=in.readLine())!=null){
out.println(line);
}
s.shutdownOutput();//out.println("over");
s.close();
}
}
class TextServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(50000);
while(true)
{
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter("TCPDemo.txt");
String line;
while((line=in.readLine())!=null){
out.println(line);
}
out.close();
s.close();
System.out.println("文件复制成功!");
}
}
}
练习:服务端多线程,实现并发登陆
/***客户端通过键盘录入用户名,服务端进行校验
如果用户存在,服务端显示XXX,已登陆;客户端显示XXX,欢迎光临
如果不存在,服务端显示XXX,尝试登陆;客户端显示XXX,用户不存在,最多校验三次
**/
import java.net.*;
import java.io.*;
class ClientThread implements Runnable
{
private Socket s;
ClientThread(Socket s){this.s = s;}
private boolean checkName(String name) throws IOException
{
BufferedReader in = new BufferedReader(new FileReader("Logname.txt"));
String line;
while((line = in.readLine())!=null)
if(line.equals(name)) return true;
return false;
}
public void run(){
int count = 3;//设置重复校验次数
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
while((count--)!=0){
String name = in.readLine();
if(checkName(name)){
System.out.println(name+",已登陆");
out.println(name+",欢迎光临");
return;
}
else{
System.out.println(name+",尝试登陆");
out.println(name+",该用户不存在");
}
}
s.shutdownOutput();
s.close();
}
catch (Exception e)
{
throw new RuntimeException("登陆异常!");
}
}
}
class LoginClient//客户端
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",20000);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line,name;
while(true){
System.out.println("请输入登陆名:");
name = input.readLine();
out.println(name);
line = in.readLine();
if(line==null) break;
else if(line.equals(name+",欢迎光临"))
{
System.out.println(line);
break;
}
else System.out.println(line);
}
input.close();
s.close();
}
}
class LoginServer//服务端
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(20000);
while(true){
Socket s = ss.accept();
new Thread(new ClientThread(s)).start();//为新加入的客户创建线程
}
}
}
第四讲. 小知识点
- InetAddress类是对IP地址的封装。
- Socke的
connect(SocketAddress endpoint)方法中,SocketAddress 叫做套接字地址,是抽象对象。其子类InetSocketAddress,
实现了(IP地址+端口号)的封装。 ServerSocket的构造方法 ServerSocket(int port, int backlog)中的int backlog指的是指定服务端最大连接数,限定了同时在线的客户数。
类
URL
代表一个统一资源定位符,它是指向互联网“资源”的指针(就是封装了域名)。URI类代表一个统一资源标识符 (URI) 引用(比URL范畴广一点)。URL的openConnecton()方法返回一个URLConnection
对象,它表示到URL
所引用的远程对象的连接(在应用层上的网络连接,里面封装了Socket,好处是去掉了http等应用层协议的消息头,只保留消息主体)。域名解析:就是把域名(主机名)演绎成IP地址,即DNS(DomainNNameSystem)。先找本地的hosts文件中查找,再在配置中指定的DNS服务器去解析域名。