黑马程序员_学习笔记_Java基础_网络编程

时间:2022-08-27 08:27:29

------------------ ASP.Net+Android+IOS开发.Net培训、期待与您交流! -------------------

一、概述

网络模型:具体通讯方式

OSI参考模型

TCP/IP参考模型

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

三要素

1、找到对方IP

2、数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识、为了方便称呼这个数字,叫做端口,是逻辑端口

3、定义通讯规则。这个通讯规则叫协议。国际组织定义了通用协议 TCP/IP。

三要素解析:

IP地址:InetAddress。

网络中设备的标识,不易记忆,可以用主机名。

本地地址为:127.0.0.1 名为Localhost

InetAddress类:通过下面的事例,了解InetAddress的基本方法。

import java.net.*;
public class IPDemo {
public static void main(String[] args) throws Exception {
InetAddress i = InetAddress.getLocalHost();
//System.out.println(i);
System.out.println("address:"+i.getHostAddress()+"\r\nname:"+i.getHostName());
//InetAddress ia = InetAddress.getByName("www.qq.com");
//System.out.println("address:"+ia.getHostAddress()+"\r\nname:"+ia.getHostName());
}
}

 端口号:用于标识进程的逻辑地址。

 网络协议:包括UDP和TCP协议。

 UDP协议

(可类比邮局寄包裹,聊天,视频会议,桌面共享等)

特点

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

2、每个数据包的大小限制在64K。

3、因为无连接,所以是不可靠协议。

4、不需要建立连接,所以速度很快。

TCP协议

(例如下载等。)

特点

1、建立连接,形成传输数据的通道。

2、在连接中进行大数据量传输。

3、通过三次握手完成连接,是可靠协议。

4、必须建立连接,效率会很低。

三次握手:发送连接请求,确认连接请求,再次确认。

 

Socket

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

通讯的两端都有Socket

网络通讯其实就是Socket间的通讯。,

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

二、UDP和TCP传输协议

UDP协议:

通过DatagramSocket类。

步骤:

发送数据:

1、建立updsocket服务。

2、提供数据,并将数据封装到数据包中。

3、通过socket服务的发送功能,将数据包发出去。

4、关闭资源。

 

接收数据

1、定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。

2、定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

3、通过socket服务的receive方法将收到的数据存入已定义好的数据包中。

4、通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。

5、关闭资源。

import java.io.*;
import java.net.*;
class Send implements Runnable{
private DatagramSocket ds;
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("172.31.5.208"),9998);
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();
String data = new String(dp.getData(),0,dp.getLength());
if("886".equals(data)){
System.out.println(ip+"离开了聊天室");
break;
}
System.out.println(ip);
System.out.println(data);
}
}
catch(Exception e ){
throw new RuntimeException("接收失败!");
}
}
}
public class ChatDemo{
public static void main(String[] args)throws Exception {
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(9998);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}

 

TCP协议:

客户端对应Socket,服务端对应ServerSocket。

客户端步骤:

1、创建Socket服务,并指定要连接的主机和端口。

2、将数据写入该流中。通过网络发送给服务端。

3、获取Socket流中的输入流,将服务端反馈的数据获取并打印。

4、关闭客户端资源。

 

服务端步骤:

1、建立服务端的Socket服务。通过ServerSocket。并监听端口。

2、获取连接过来的客户端对象。通过ServerSocket的accept方法。所以方法是阻塞式的。

3、客户端如果发过来数据,那么服务端要使用对应的客户端对象。并获取到该客户端对象的读取流来读取发过来的数据,打印在控制台上。

4、关闭服务端。(可选)

 

import java.io.*;
import java.net.*;
class TcpClient2
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("172.31.5.208",10009);
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(10009);
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();
}
}

 

练习1:建立一个文本转换服务器

客户端给服务端发送文本,服务端将文本转成大写,再返回给客户端

而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。

import java.io.*;
import java.net.*;
class TransClient{
public static void main(String[] args) throws Exception{
Socket s = new Socket("172.31.4.20",10010);
//定义读取键盘数据的流对象。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入Socket输出流,发送给服务端。
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//定义一个Socket读取流,读取服务端返回的信息。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufOut.write(line);
bufOut.newLine();
bufOut.flush();
String str = bufIn.readLine();
System.out.println("Server;"+str);
}
bufr.close();
s.close();
}
}
class TransServer{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10010);
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()));
String line = null;
while((line = bufIn.readLine())!=null){
System.out.println(line);
bufOut.write(line.toUpperCase());
bufOut.newLine();
bufOut.flush();
}
s.close();
ss.close();
}
}


练习2:上传图片

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();
}
}

 

三、其他相关

1、多线程并发

由上一节上传图片的练习可知,这样的服务端有局限性,当一个客户端连接上后,被服务端获取到,服务端就开始执行。

这时,另一个客户端想要连接,只有等待。因为服务端还没有处理完A客户端的请求。所以暂时获取不到这个客户端对象。

为了让多个客户端并发访问服务端,服务端需要将每一个客户端封装到一个单独线程。

这样,就可以同时处理多个客户端请求。

只要明确了每一个客户端要在服务端执行的代码,将该代码存入run方法中,就可以使用多线程技术了。

下面是修改后上传图片的代码,运用了多线程技术,并发上传图片:

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("图片格式错误,请选择jpg格式的图片");
return ;
}
if(file.length()>1024*1024*5){
System.out.println("文件过大,没安好心");
return ;
}
Socket s = new Socket("172.31.4.20",10080);
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();
}
}
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s=s;
}
public void run(){
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try{
System.out.println(ip+".........connected");
InputStream in = s.getInputStream();
File file = new File(ip+"("+count+")"+".jpg");
while(file.exists())
file = new File(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(10080);
while(true){
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
//ss.close();
}
}

 

练习:多客户端并发登录。

/*
客户端通过键盘录入用户名,
服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx已登录。
并在客户端显示xxx欢迎观临。
如果该用户名不存在,在服务端显示xxx尝试登陆。
并在客户端显示xxx该用户不存在。
最多登陆三次。
*/
import java.io.*;
import java.net.*;
class LoginClient{
public static void main(String[] args) throws Exception{
Socket s = new Socket("172.31.4.20",10087);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
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(10087);
while(true){
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}

 

2、浏览器相关

(1)

客户端:浏览器

服务端:自定义

(2)

客户端:浏览器

服务端:Tomcat服务器。

(3)

客户端:自定义

服务端:Tomcat服务器

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();
}
}

 

3、URL和URLConnection

URL方法简介:

String getFile()

          获取此 URL 的文件名。

 String getHost()

          获取此 URL 的主机名(如果适用)。

 String getPath()

          获取此 URL 的路径部分。

 int getPort()

          获取此 URL 的端口号。

 StringgetProtocol()

          获取此 URL 的协议名称。

 String getQuery()

          获取此 URL 的查询部分。

 

利用URLConnection封装的方法,更能简化程序。

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class MyIEByGUI2{
private Frame f;
private TextField tf;
private Button but;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBut;
MyIEByGUI2(){
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){
new RuntimeException("错误");
}
}
});
but.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
showDir();
}
catch (Exception ex){
new RuntimeException("错误");
}
}
});

f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
private void showDir()throws Exception{
ta.setText("");
String urlPath = tf.getText();//http://192.168.1.254:8080/myweb/demo.html
URL url = new URL(urlPath);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
ta.setText(new String(buf,0,len));
}
public static void main(String[] args) {
new MyIEByGUI2();
}
}


4、小知识点

Socket 空参数构造函数。用connect连接。

SocketAddress是一个抽象类,InetSocketAddress是他的子类,实现了IP套接字地址。

Backlog队列最大长度。能连接客户端的最大限度。

  

5、域名解析

想要将主机名翻译成IP地址,需要域名解析。需要DNS域名解析服务器。

host文件可用于屏蔽一些恶意网址,即名称写入host中,将IP地址改为本机的回环地址,那么当出现连接时,就会直接返回本地,不会连接上了。


------------------ ASP.Net+Android+IOS开发.Net培训、期待与您交流! ------------------

详细请查看:http://edu.csdn.net