---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

14、网络编程

14.1网络模型

1、OSI参考模型

2、TCP/IP参考模型

现在在网际层和传输层,javaweb在应用层。传输层常见的协议是TCP和UDP协议;网际层常见的协议就是IP。应用层协议HTTP、FTP。

3、OSI与TCP/IP参考模型图示

14.2网络通讯三个要素

14.2.1IP地址:对象InetAddress

•   网络中设备的标识

•   不易记忆,可用主机名

•   本地回环地址:127.0.0.1  主机名:localhost(可改)

14.2.2端口号

•   用于标识进程的逻辑地址,不同进程的标识

•   有效端口:0~65535,其中0~1024系统使用或保留端口。

14.2.3传输协议

•   通讯的规则

•   常见协议:TCP,UDP

14.2.4相关说明:

1、端口:不是物理端口,是一个数字标识

2、在命令行Ping 127.0.0.1可以测试网卡

3、常用端口:web:80,tomcat:8080,MySQL:3306(可以更改)

14.2.5IP地址常用方法示例

import java.net.*;

class  IPDemo

{

publicstatic void main(String[] args) throws Exception

{

//抛出唯有主机异常,获取本地主机名和IP地址,静态方法

InetAddressi = InetAddress.getLocalHost();

System.out.println(i.toString());

//分别获取主机名和IP地址,联网情况下不一定获得主机名,有可能解析不了

System.out.println("address:"+i.getHostAddress());

System.out.println("name:"+i.getHostName());

//给定主机名或IP地址,返回IP地址和主机名

InetAddressia = InetAddress.getByName("abc-PC");

System.out.println("address:"+ia.getHostAddress());

System.out.println("name:"+ia.getHostName());

}

}

14.3UDP、TCP和Socket(必须会)

14.3.1UDP(面向无连接)

a)  将数据及源和目的封装成数据包中,不需要建立连接

b)  每个数据报的大小在限制在64k内(分成多包发送)

c)  因无连接,是不可靠协议,收不到则数据丢失

d)  不需要建立连接,速度快

e)  应用UDP协议的程序:聊天,视频会议,桌面共享

14.3.2TCP(面向连接)

f)  建立连接,形成传输数据的通道

g)  在连接中进行大数据量传输

h)  通过三次握手完成连接,是可靠协议

i)  必须建立连接,效率会稍低

j)  应用TCP协议的程序:打电话,下载

14.3.3Socket

l Socket就是为网络服务提供的一种机制。

l 通信的两端都有Socket。

l 网络通信其实就是Socket间的通信。

l 数据在两个Socket间通过IO传输。

Socket翻译过来是:插座或者套接字。Socket370个针脚CPU,Socket478个针脚的CPU。

网络编程就是Socket编程

14.4UDP

14.4.1UDP中的DatagramSocket和DatagramPacket

DatagramSocket:此类表示发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。在 DatagramSocket 上总是启用 UDP 广播发送。为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。在某些实现中,将DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。

DatagramPacket:此类表示数据报包。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。DatagramPacket对象的构造函数可以接收和发送数据包,当构造函数中含有IP地址的就是发送数据包的。

14.4.2UDP传输步骤

发送端与接收端是两个独立的运行程序

192.168.1.0是一个网络地址,192.168.1.255是这个网段中的广播地址

14.4.3UDP的发送端和接收端

14.4.3.1发送端建立的步骤

需求:通过udp传输方式,将一段文字数据发送出去。,
思路:
1,建立updsocket服务,端点(邮局)。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送功能,将数据包发出去。
4,关闭资源。
*/
import java.net.*;
class  UdpSend
{
public static void main(String[] args) throws Exception
{
//1,创建udp服务。通过DatagramSocket对象。定义数字标识,否则默认分配,多次运行后的端口效果不同,因为还在内存中使用没有被释放,所以端口号会被顺延。
DatagramSocket ds = new DatagramSocket(8888);
//2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port) 参数说明:buf字节数组,length长度,address接收端IP地址,port端口
byte[] buf = "udp ge men lai le ".getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000);
//3,通过socket服务,将已有的数据包发送出去。通过send方法。
ds.send(dp);
//4,关闭资源。
ds.close();
}
}

14.4.3.2接收端

需求:
定义一个应用程序,用于接收udp协议传输的数据并处理的。
思路:
1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能,将这些不同的数据取出。打印在控制台上。
5,关闭资源。
import java.net.*;
class  UdpRece
{
public static void main(String[] args) throws Exception
{
//1,创建udp socket,建立端点。定义数字标识10000,若不定义则默认分配。不可以把此句代码加入到while循环中,因为会抛出绑定异常(BindException),因为端口已被使用(程序关掉,有可能还在内存中没有被释放),不可再次创建端口Socket对象
DatagramSocket ds = new DatagramSocket(10000);
while(true)//接收端一直存在,不是死循环,因为receive方法是阻塞是方法
{
//2,定义数据包。用于存储数据。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3,通过服务的receive方法将收到数据存入数据包中。
ds.receive(dp);//阻塞式方法。没数据就等待
//4,通过数据包的方法获取其中的数据。
//获取IP对象再获取IP字符串
String ip = dp.getAddress().getHostAddress();
//获取字节数组,封装成字符串,
String data = new String(dp.getData(),0,dp.getLength());
//获取端口
int port = dp.getPort();
//打印信息
System.out.println(ip+"::"+data+"::"+port);
}
//5,关闭资源
ds.close();
}
}

14.4.4UDP键盘录入数据发送

import java.net.*;
import java.io.*;
//发送端
class  UdpSend2
{
public static void main(String[] args) throws Exception
{
//1、建立Socket服务
DatagramSocket ds = new DatagramSocket();
//2、键盘录入
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//3、读取,其中readLine方法也是阻塞式方法
String line = null;
while((line=bufr.readLine())!=null)
{
if("886".equals(line))//结束标记
break;
byte[] buf = line.getBytes();//变成数组
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001); //封装成包,使用广播地址,向在此网段的所有接收端发信息
ds.send(dp);
}
ds.close();
}
}
//接收端,最好不要关闭,因为要等待接收。
class  UdpRece2
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(10001);
while(true)
{
byte[] buf = new byte[1024];//可以创建64K大小
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"说"+data);
}
}
}

14.4.5聊天程序

有收数据的部分和发数据的部分,这两部分需要同时执行。那就需要用到多线程技术。一个线程控制收,一个线程控制发。因为收和发动作是不一致的,所以要定义两个run方法。而且这两个方法要封装到不同的类中。
import java.io.*;
import java.net.*;
class Send implements Runnable
{
private DatagramSocket ds;//建立Socket服务端
public Send(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null)
{
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10002);
ds.send(dp);
if("886".equals(line))
break;
}
}
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();//先看看IP地址
String data = new String(dp.getData(),0,dp.getLength());
if("886".equals(data))
{
System.out.println(ip+"....离开聊天室");
break;
}
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);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}

14.5TCP

14.5.1Socket和ServerSocket

Socket(客户端对应的对象)

此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。

ServerSocket(服务器端对应的对象)

此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。服务器套接字的实际工作由 SocketImpl 类的实例执行。应用程序可以更改创建套接字实现的套接字工厂来配置它自身,从而创建适合本地防火墙的套接字。也可以构造一个带端口号和int backlog队列的最大长度,就是能连接到服务器的客户端的最大同时个数(50)。

14.5.2客户端和服务端创建的基本思路

基本思路(客户端)

l 客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。

l 连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream(),getOutputStream()获取即可。

l 与服务端通讯结束后,关闭Socket。

基本思路(服务端)

l 服务端需要明确它要处理的数据是从哪个端口进入的。

l 当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。

l 当该客户端访问结束,关闭该客户端。

14.5.3TCP传输最容易出现的问题

l 客户端连接上服务端,两端都在等待,没有任何数据传输。

l 通过例程分析:

•   因为read方法或者readLine方法是阻塞式。

l 解决办法:

•   自定义结束标记

•   使用shutdownInput,shutdownOutput方法。

14.5.4TCP客户端

通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。因为tcp是面向连接的。所以在建立socket服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。也可以创建空参数的构造函数,是因为有一个connect方法可以连接到目的服务器。
需求:给服务端发送一个文本数据
步骤:
1,创建Socket服务。并指定要连接的主机和端口。
*/
import java.io.*;
import java.net.*;
class  TcpClient
{
public static void main(String[] args) throws Exception
{
//1、创建客户端的socket服务。指定目的主机和端口
Socket s = new Socket("192.168.1.254",10003);
//2、为了发送数据,应该获取socket流中的输出流。
OutputStream out = s.getOutputStream();
//3、写出
out.write("tcp ge men lai le".getBytes());
s.close();
}
}

14.5.5TCP服务端(必须先启动)

需求:定义端点接收数据,并将打印到控制台。
1,建立服务端的socket服务。通过构造函数ServerSocket();并监听一个端口。
2,获取连接过来的客户端对象。通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。并打印在控制台。
4,关闭服务端。(可选)
class  TcpServer
{
public static void main(String[] args) throws Exception
{
//1、建立服务端socket服务。并监听一个端口。
ServerSocket ss = new ServerSocket(10003);
//2、通过accept方法获取连接过来的客户端对象。
while(true)
{
Socket s = ss.accept();
//获取客户端IP地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//3、获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream in = s.getInputStream();//源是网络流
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭客户端.
}
//ss.close();//关闭服务器端(可选)
}
}

14.6TCP应用

14.6.1TCP传输的客户端和服务端的互访(一来一回)

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
客户端:
1,建立socket服务。指定要连接主机和端口。
2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
4,关闭客户端资源。
import java.io.*;
import java.net.*;
class TcpClient2
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("192.168.1.254",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();//写反馈信息
Thread.sleep(10000);
out.write("哥们收到,你也好".getBytes());
s.close();
ss.close();
}
}

14.6.2文本转换服务器

需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务端会将文本转换成大写再返回给客户端。而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
分析:
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
数据源:键盘录入。
数据目的:网络设备,网络输出流。
而且操作的是文本数据,可以选择字符流。
步骤
1,建立服务。
2,获取键盘录入。
3,将数据发给服务端。
4,获取服务端返回的大写数据。
5,结束,关资源。
服务端:
数据源:socket读取流。
数据目的:socket输出流。
都是文本,装饰。
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。
import java.io.*;
import java.net.*;
class  TransClient
{
public static void main(String[] args) throws Exception
{
//创建Socket服务
Socket s = new Socket("192.168.1.254",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;
out.println(line);
//                     bufOut.write(line);//写入输出流
//                     bufOut.newLine();//使得读取换行
//                     bufOut.flush();//刷新写入缓冲区
String str =bufIn.readLine();//读取输入流
System.out.println("server:"+str);
}
bufr.close();//关闭键盘录入
s.close();//关闭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()));
//简化一下,接收字符流和字节流,自动刷新true
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=bufIn.readLine())!=null)
{
System.out.println(line);
//println自动刷新,当设置为true时,是有效的自动刷新。
out.println(line.toUpperCase());
//                     bufOut.write(line.toUpperCase());
//                     bufOut.newLine();//结束标记
//                     bufOut.flush();//刷新写入缓冲区
}
s.close();
ss.close();
}
}
/*
该例子出现的问题。
现象:客户端和服务端都在莫名的等待。
为什么呢?
因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等,而导致两端,都在等待。
*/

14.6.3TCP上传文本文件

import java.io.*;
import java.net.*;
class  TextClient
{
public static void main(String[] args) throws Exception
{
//此处要抛异常
Socket s = new Socket("192.168.1.254",10006);
//此处抛异常
BufferedReader bufr = new BufferedReader(new FileReader("IPDemo.java"));//最好将其封装成文件然后判断。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=bufr.readLine())!=null)
{
out.println(line);
}
//关闭客户端的输出流。相当于给流中加入一个结束标记-1.Tomcat服务器用的也是这种结束标记,是单独的一个空行,用于区分字段,头字段与HTTP字段
              s.shutdownOutput();
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = bufIn.readLine();
System.out.println(str);
bufr.close();
s.close();
}
}
class  TextServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//文件名的处理方式,应当对同名文件进行处理,比如时间戳
PrintWriter out  = new PrintWriter(new FileWriter("server.txt"),true);
String line = null;
while((line=bufIn.readLine())!=null)
{
//if("over".equals(line))
//break;
out.println(line);
}
//服务端回馈客户端的信息
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功");
out.close();
s.close();
ss.close();
}
}

14.6.4TCP上传图片文件

需求:上传图片。
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
import java.io.*;
import java.net.*;
class  PicClient
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("192.168.1.254",10007);
FileInputStream fis = new FileInputStream("c:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//告诉服务端数据已写完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
服务端
class  PicServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10007);
Socket s = ss.accept();//阻塞式方法
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("server.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();
}
}

14.6.5客户端并发上传图片

需求:客户端并发上传图片。
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
import java.io.*;
import java.net.*;
class  PicClient
{
public static void main(String[] args)throws Exception
{
if(args.length!=1)//传入了参数
{
System.out.println("请选择一个jpg格式的图片");
return ;
}
File file = new File(args[0]);
if(!(file.exists() && file.isFile()))
{
System.out.println("该文件有问题,要么不存在,要么不是文件");
return ;
}
if(!file.getName().endsWith(".jpg"))
{
System.out.println("图片格式错误,请重新选择");
return ;
}
if(file.length()>1024*1024*5)
{
System.out.println("文件过大,没安好心");
return ;
}
Socket s = new Socket("192.168.1.254",10007);
FileInputStream fis = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//告诉服务端数据已写完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
服务端
这个服务端有个局限性。当A客户端连接上以后。被服务端获取到。服务端执行具体流程。这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求,还没有循环回来执行下次accept方法。所以,暂时获取不到B客户端对象。
那么为了可以让多个客户端同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。
//所有的服务器都是这种原理
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)//传入一个客户端
{
this.s = s;
}
public void run()//复写run方法,封装客户端
{
int count = 1;//局部数据
String ip  = s.getInetAddress().getHostAddress();
try
{
System.out.println(ip+"....connected");
InputStream in = s.getInputStream();
File dir =  new File("d:\\pic");//创建目录
File file = new File(dir,ip+"("+(count)+")"+".jpg");
while(file.exists())//如果多个文件存在
file = new File(dir,ip+"("+(count++)+")"+".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
fos.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}
class  PicServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10007);
while(true)
{
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
//ss.close();
}
}

14.6.6TCP客户端并发登录

客户端通过键盘录入用户名。
服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx,已登陆。
并在客户端显示 xxx,欢迎光临。
如果该用户存在,在服务端显示xxx,尝试登陆。
并在客户端显示 xxx,该用户不存在。
最多就登录三次。
import java.io.*;
import java.net.*;
class  LoginClient
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.254",10008);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//读取键盘录入,ctrl+c就是空
//创建输出数据流
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//读取输入流
BufferedReader bufIn =new BufferedReader(new InputStreamReader(s.getInputStream()));
for(int x=0; x<3; x++)
{
String line = bufr.readLine();
if(line==null)
break;
out.println(line);//发出去
String info = bufIn.readLine();
System.out.println("info:"+info);
if(info.contains("欢迎"))
break;
}
bufr.close();
s.close();
}
}
class UserThread implements Runnable
{
private Socket s;
UserThread(Socket s)
{
this.s = s;
}
public void run()
{
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
try
{
for(int x=0; x<3; x++)
{
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufIn.readLine();
if(name==null)
break;
BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
boolean flag = false;
while((line=bufr.readLine())!=null)
{
if(line.equals(name))
{
flag = true;
break;
}
}
if(flag)
{
System.out.println(name+",已登录");
out.println(name+",欢迎光临");
break;
}
else
{
System.out.println(name+",尝试登录");
out.println(name+",用户名不存在");
}
}
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"校验失败");
}
}
}
class  LoginServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10008);
while(true)
{
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}

14.6.7TCP客户端与服务端的自定义

1,
客户端:浏览器 (telnet)
服务端:自定义。
2,
客户端:浏览器。
服务端:Tomcat服务器。(纯java编写)
3,
客户端:自定义。(图形界面)
服务端:Tomcat服务器。

14.6.7.1浏览器和telnet访问自定义服务器

import java.net.*;
import java.io.*;
class ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
//客户端请求信息
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
//客户端回馈信息
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>客户端你好</font>");
s.close();
ss.close();
}
}
//可以在浏览器登录如下:访问服务器IP地址,如:192.168.1.254:11000
//可以在DOS下telnet远程登录如下:telnet 192.168.1.254 11000
Telnet是Window系统提供的远程登录,在DOS命令行下登录网络中的任意一台主机,可以对这台主机进行命令式的配置,包括路由器和交换机。

14.6.7.2模仿浏览器客户端

import java.io.*;
import java.net.*;
class MyIE
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("192.168.1.254",8080);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/demo.html HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 192.168.1.254:11000");
out.println("Connection: closed");
out.println();
out.println();
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
s.close();
}
}

14.6.7.3浏览器发送的请求信息

http://192.168.1.254:11000/myweb/demo.html
//请求消息头
GET /myweb/demo.html HTTP/1.1
//浏览器支持的应用程序
Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/QVOD, application/QVOD,
//浏览器支持的语言
Accept-Language: zh-cn
//浏览器支持的压缩方式
Accept-Encoding: gzip, deflate
//用户代理
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)
//访问的主机和端口
Host: 192.168.1.254:11000
//连接状态
Connection: Keep-Alive
//消息头结束标记为一个空行
*/

14.6.7.4模仿浏览器的图形界面

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class  MyIEByGUI
{
private Frame f;
private TextField tf;
private Button but;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBut;
MyIEByGUI()
{
init();
}
public void init()
{
f = new Frame("my window");
f.setBounds(300,100,600,500);
f.setLayout(new FlowLayout());
tf = new TextField(60);
but = new Button("转到");
ta = new TextArea(25,70);
d = new Dialog(f,"提示信息-self",true);
d.setBounds(400,200,240,150);
d.setLayout(new FlowLayout());
lab = new Label();
okBut = new Button("确定");
d.add(lab);
d.add(okBut);
f.add(tf);
f.add(but);
f.add(ta);
myEvent();
f.setVisible(true);
}
private void  myEvent()
{
okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showDir();
}
catch (Exception ex)
{
}
}
});
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showDir();
}
catch (Exception ex)
{
}
}
});
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
private void showDir()throws Exception//切割字符串
{
ta.setText("");
String url = tf.getText();//http://192.168.1.254:8080/myweb/demo.html
int index1 = url.indexOf("//")+2;
int index2 = url.indexOf("/",index1);
String str = url.substring(index1,index2);
String[] arr = str.split(":");
String host = arr[0];
int port = Integer.parseInt(arr[1]);
String path = url.substring(index2);
//ta.setText(str+"...."+path);
Socket s = new Socket(host,port);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET "+path+" HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 192.168.1.254:11000");
out.println("Connection: closed");
out.println();
out.println();
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)
{
ta.append(line+"\r\n");
}
s.close();
}
public static void main(String[] args)
{
new MyIEByGUI();
}
}

14.7URL

URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。
URI要比URL的范围要大,条形码(SBI)也属于URI的范畴。

14.7.1URL常用方法

String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部(参数) //使用频率相当的高

14.7.2URL常用方法示例

import java.net.*;
class URLDemo
{
public static void main(String[] args) throws MalformedURLException
{
//信息用问号分割,用&连接,信息都是以键值对的形式存在的。
URL url = new URL("http://192.168.1.254:8080/myweb/demo.html?name=haha&age=30");
System.out.println("getProtocol() :"+url.getProtocol());//http
System.out.println("getHost() :"+url.getHost());//192.168.1.254
//指定端口返回端口号8080,未指定端口号时返回-1
System.out.println("getPort() :"+url.getPort());
System.out.println("getPath() :"+url.getPath());// /myweb/demo.html
///myweb/demo.html?name=haha&age=30
System.out.println("getFile() :"+url.getFile());
System.out.println("getQuery() :"+url.getQuery());//name=haha&age=30
/*int port = getPort();
if(port==-1)
port = 80;//web默认为80端口
//getPort()==-1
*/
}
}

14.7.3URL的URLConnection对象

openConnection

public URLConnection openConnection() throws IOException

返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 每次调用此 URL 的协议处理程序的 openConnection 方法都打开一个新的连接。如果URL 的协议(例如,HTTP 或 JAR)存在属于以下包或其子包之一的公共、专用 URLConnection 子类:java.lang、java.io、java.util、java.net,返回的连接将为该子类的类型。例如,对于 HTTP,将返回 HttpURLConnection,对于 JAR,将返回 JarURLConnection。

14.7.4URLConnectionDemo连接对象示例

import java.net.*;
import java.io.*;
class  URLConnectionDemo
{
public static void main(String[] args) throws Exception
{
URL url = new URL("http://192.168.1.254:8080/myweb/demo.html");
URLConnection conn = url.openConnection();
System.out.println(conn);
InputStream in = conn.getInputStream();//不用关闭
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
}
}

14.8域名解析及应用

14.8.1域名解析图

14.8.2域名解析应用

应用一:

配置IP地址,hosts文件使其对应,可以加快上网速度

应用二:

收费软件进行更新,会对注册码进行检查,对网址发请求,,将请求文件设置为本地主机。

应用三:

广告页面还有一些恶意网站,将网站的映射配置为本地主机,屏蔽网站

14.9网络架构

C/S:Client/Server
客户端,服务端。
特点:
1,需要在客户端和服务端都需要按照编写的软件。
2,维护较麻烦。
好处:可以减轻服务端的压力,如网络游戏。
B/S:Browser/Server
浏览器 ,服务端。
1,客户端不用单独编写软件。
因为客户端用的就是浏览器。
2,对于软件升级,只要考虑服务端即可。
弊端:所有的程序都运行在服务端,客户端的浏览器毕竟解析能力较弱。对游戏等。
import java.net.*;
class ScanDemo
{
public static void main(String[] args)
{
for(int x=130; x<145; x++)
{
try
{
Socket s = new Socket("192.168.1.254",x);
System.out.println(x+"...open");
}
catch (Exception e)
{
System.out.println(x+"...closed");
}
}
}
}

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

黑马程序员---网络编程相关推荐

  1. 黑马程序员--网络编程知识点总结

    --- android培训.java培训.期待与您交流! ---- 网络编程三要素 IP,端口,协议. 1.IP:在Internet上,每一台通信实体(这个通信实体可以是路由器的某一端口,计算机和服务 ...

  2. 黑马程序员 网络编程2

    ------------------android培训. java培训.期待与您交流!------------------- 网络编程2 昨天主要讲述了UDP连接,今天再讲讲TCP连接 在" ...

  3. 黑马程序员 网络编程1

    ------------------android培训. java培训.期待与您交流!------------------- 网络编程1 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通 ...

  4. 黑马程序员——网络编程(二)--TCP网络程序、访问Internet网络资源

    -------  android培训.java培训.期待与您交流! ---------- 第一部分 TCP网络程序 一.TCP网络程序的工作原理 TCP客户端程序与TCP服务器程序的交互过程: (1) ...

  5. 黑马程序员 — 网络编程

    -------android培训.java培训.期待与您交流! ---------- 网络编程 什么是网络编程: 能够接受另一台计算机发送过来的数据或者能够向另一台计算机发送数据的程序叫做网络程序 U ...

  6. 黑马程序员——网络编程及正则表达式

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 网络编程 网络模型: OSI参考模型.TCP/IP参考模型 1.找对方IP 2.数据发到对法指定 ...

  7. 黑马程序员--网络编程

    端口号的范围:0-65535,其中0-1024系统已经占用,例如:WEB端口:80:mysql端口:3306:tomcat:8080: 在网络通信里, 1.传输层协议: TCP协议,类似于打电话(下载 ...

  8. 黑马程序员——网络编程

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 网络模型   1)OSI参考模型   2)TCP/IP参考模型 网络通讯要素:IP地址.端口号. ...

  9. 黑马程序员并发编程笔记(二)--java线程基本操作和理解

    3.java进程的基本操作 3.1.创建进程 方法一,直接使用 Thread // 构造方法的参数是给线程指定名字,,推荐给线程起个名字(用setName()也可以) Thread t1 = new ...

最新文章

  1. 常惠琢 201771010102《面向对象程序设计(java)》第七周学习总结
  2. CoolPad backdoor CoolReaper
  3. 人人FED CSS编码规范
  4. JSONP 初步学习--但是还是有疑问
  5. 读取CRM 产品主数据所有属性的API
  6. va_list和vsnprintf、getopt
  7. ora-28500 ora-02063 mysql_oracle dblink mysql 报错ORA-28500
  8. 轨迹跟踪主要方法_带你入门多目标跟踪(一)领域概述
  9. ORA-01552 :非系统表空间 'xxxx'不能使用系统回退段
  10. EXTJS 双层表头 记录
  11. MySQL06:变量、存储过程和函数、流程控制结构
  12. Mblock使用时钟中断显示4段数码管的值
  13. java+biz+impl_为何在UserBizImpl实体类注入时…-体系课
  14. 干货分享 | 4万字全面解读数据中台、数据仓库、数据湖(建议收藏)
  15. 巴菲特致股东的一封信:1991年
  16. 文昌京东配送小哥的那些骄傲事
  17. 关于violate变量的使用
  18. MapObject 控件的使用之加入图层(作者/张松伟)
  19. VR与智能家居有哪些可能的结合形式?可为智能家居带来哪些好处?
  20. 汇编ret ,retf ,iret ,int指令详解

热门文章

  1. Excel2003 去除重复项
  2. 如何用python批量下载数据_如何用python从wind中批量导出数据
  3. KNN算法及KNN的优化算法-加权KNN
  4. KVM安装/libvirt没有启动成功找不到/var/run/libvirt/libvirt-sock
  5. MFC使用CFile类进行输入输出到文本文件
  6. 网络基础 — 路由器的原理和作用
  7. IntelliJ IDEA下载安装教程
  8. libusb使用指南
  9. 关于谢尔宾斯基三角(Sierpinski)的讲解
  10. 宝塔服务器源代码修改记录,宝塔BT面板修改相关记录,所有插件免费用