黑马程序员——网络编程

------- android培训java培训、期待与您交流! ----------

 

网络编程概述

OSI参考模型;物理-数据链路-网络-传输-会话-表示-应用层。

TCP/IP参考模型:主机至网络层-网际层-传输层-应用层。

我们初期是在传输层,后期在应用层编程。

  小知识点:可以用ping 127.0.0.1,测试网卡是否有问题。

端口号:0~25535 其中,0~1024被系统保留了。给系统应用程序用。

常见默认端口:

web 80

Tomcat服务器默认:8080

Mysql 3306

 

网络通讯三要素:IP 端口 传输协议

传输层所用的协议是:TCPUDP

网络层最常见的协议是:IP

应用层协议:httpfttp

 

IP地址:

 

java.net包中的类InetAddress是用来描述IP地址的类。

String getHostAddress()返回 IP 地址字符串(以文本表现形式)。

String getHostName()获取此 IP 地址对象的主机名。

以上两个获取方法,以第一个为主。因为获取主机名需要解析,速度要慢。

 

static InetAddress getLocalHost() 返回本地主机(主机名和IP地址)。抛异常UnknownHostException;

 

有的一个主机名会对应多个IP(有多个服务器),可用以下方式获取:

static InetAddress[] getAllByName(String host) 在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。

在网络中获取任意一台主机的IP地址:(后面常用到的)

static InetAddress getByName(String host) 参数可以传递IP地址或主机名。 在给定主机名的情况下确定主机的 IP 地址。

如果地址和其对应的主机名没有在网络上,则返回的名字还是IP地址。获取名字,需要解析,所以在网络上获取主机的名字会较慢。

 

TCP和UDP区别:

UDP

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

• 每个数据报的大小在限制在64k内

• 因无连接,是不可靠协议

• 不需要建立连接,速度快

 

TCP

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

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

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

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

 

Socket:套接字。

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

通信的两端都有Socket。

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

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

 

 

UDP传输:

DatagramSocket与DatagramPacket

建立发送端,接收端。

建立数据包。

调用Socket的发送接收方法。

关闭Socket。

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

 

发送端:

在发送端,要在数据包对象中明确目的地IP及端口。

DatagramSocket ds = new DatagramSocket();

byte[] by = “hello,udp”.getBytes();

DatagramPacket dp = newDatagramPacket(by,0,by.length,

InetAddress.getByName(“127.0.0.1”),10000);

ds.send(dp);

ds.close();

 

接收端:

在接收端,要指定监听的端口。

DatagramSocket ds = newDatagramSocket(10000);

byte[] by = new byte[1024];

DatagramPacket dp = newDatagramPacket(by,by.length);

ds.receive(dp);

String str = newString(dp.getData(),0,dp.getLength());

System.out.println(str+"--"+dp.getAddress());

ds.close();

/*

 * 创建UDP传输的发送端。

 * 思路:

 * 1,建立udp的socket服务。

 * 2,将要发送的数据封装到数据包中。

 * 3,通过udp的socket服务将数据包发送出去。

 * 4,关闭socket服务。

 

 举例如下:

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.net.SocketException;

import java.net.UnknownHostException;

 

public class UDPSendDemo {

/**

 *@param args

 *@throws IOException 

 */

public static void main(String[] args)throws IOException {

System.out.println("发送端启动......");

//1,udpsocket服务。使用DatagramSocket对象。

DatagramSocket ds = newDatagramSocket(8888);

//2,将要发送的数据封装到数据包中。

String str = "udp传输演示:哥们来了!";

//使用DatagramPacket将数据封装到的该对象包中。

byte[] buf = str.getBytes();

DatagramPacket dp =

newDatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);

//3,通过udp的socket服务将数据包发送出去。使用send方法。

ds.send(dp);

//4,关闭资源。

ds.close();

}

}

 

* 建立UDP接收端的思路。

 * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。

 * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.

 * 3,使用socket服务的receive方法将接收的数据存储到数据包中。

 * 4,通过数据包的方法解析数据包中的数据。

 * 5,关闭资源 

 

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

 

public class UDPReceDemo {

public static void main(String[] args)throws IOException {

System.out.println("接收端启动......");

//1,建立udp socket服务。

DatagramSocket ds = newDatagramSocket(10000);

//2,创建数据包。

byte[] buf = new byte[1024];

DatagramPacket dp = newDatagramPacket(buf,buf.length);

//3,使用接收方法将数据存储到数据包中。

ds.receive(dp);//阻塞式的。

//4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。

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

int port = dp.getPort();

String text = newString(dp.getData(),0,dp.getLength());

System.out.println(ip+":"+port+":"+text);

//5,关闭资源。

ds.close();

}

}

主要方法:

DatagramSocket 此类表示用来发送和接收数据报包的套接字。

DatagramSocket(int port)
          创建数据报套接字并将其绑定到本地主机上的指定端口

close()
          关闭此数据报套接字

send(DatagramPacket p)
          从此套接字发送数据报包。

receive(DatagramPacket p)
          从此套接字接收数据报包。  阻塞式接收。

DatagramPacket(byte[] buf, int length, InetAddress address,int port)
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

DatagramPacket(byte[] buf, int length)
          构造 DatagramPacket,用来接收长度为 length 的数据包。

通过数据包获取信息 的方法:

InetAddress getAdress(); 返回某台机器的IP地址。

Byte[] getDate(); 返回数据包中的信息

int getLength(); 返回将要发送或接收到的数据长度。

int getport(); 返回发动数据包的主机端口号。

 

UDP-键盘录入方式数据聊天模式,接受端设置循环,发送端用标准输入读取流:

importjava.net.*;

import java.io.*;

class UdpSend {

       publicstatic void main(String[] args) throws Exception {

              DatagramSocketds = new DatagramSocket(8888);

              BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));

              Stringline = null;

              byte[]buf = new byte[1024*64];

              while((line=br.readLine())!=null){

                     if("886".equals(line))

                     break;

                     buf= line.getBytes();

                     DatagramPacketdp = newDatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.109"),10000);

                     ds.send(dp);

              }

              ds.close();

       }

}

 

class UdpRec {

       publicstatic void main(String[] args) throws Exception  {

              DatagramSocketds = new DatagramSocket(10000);

              while(true){

                     byte[]buf = new byte[1024];

                     DatagramPacketdp = new DatagramPacket(buf,buf.length);

                     ds.receive(dp);

                     Stringip = dp.getAddress().getHostAddress();

                     byte[]data = dp.getData();

                     intport = dp.getPort();

                     System.out.println(ip+new String(data,0,dp.getLength()) );

              }

       }

}

如果将发送端数据包的IP最后一位改为255,就编程了发广播,则相同网段内的所有电脑对应的端口(此为10000)都能收到。

 

TCP:

 

CP传输

演示tcp传输

1.tcp分客户端和服务器。

2.客户端对应的对象是Socket.服务端对应的对象是ServerSocket.

 

客户端,

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

 

步骤:

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

2.        为了发送数据,应该获取Socket流中的输出流。并调用其Write(byte[])方法将数据写入流中。

3.        关闭Socket。

import java.io.IOException;

import java.io.OutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

 

public class ClientDemo {

public static void main(String[] args)throws UnknownHostException, IOException

{

//创建客户端socket服务。

Socket socket = newSocket("192.168.1.100",10002);

//获取socket流中的输出流。 

OutputStream out =socket.getOutputStream();

//使用输出流将指定的数据写出去。

out.write("tcp演示:哥们又来了!".getBytes());

//关闭资源。

socket.close();

}

}

 

服务端:

1.        建立服务端的Socket服务。ServerSocket(port);并监听一个端口。

2.        获取连接过来的客户端对象。  通过ServerSocket的accept方法。没有连接就会等,所以这个方法是阻塞式的。

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

4.        关闭服务端(可选操作,因为现实中的服务器一般是不关闭的)。一般在这之前,还要关闭Socket,即调用一次,s.close();

此处指出毕老师视频中的一个错误: Socket的getAddress()方法返回的是此套接字连接的远程地址,而不是本机地址。

 

演示tcp的传输的客户端和服务端的互访。

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

代码如下:

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

public class ServerDemo {

public static void main(String[] args)throws IOException {

//1创建服务端对象。

ServerSocket ss = new ServerSocket(10002);

//2,获取连接过来的客户端对象。

Socket s = ss.accept();//阻塞式.

String ip =s.getInetAddress().getHostAddress();

//3,通过socket对象获取输入流,要读取客户端发来的数据

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

String text = new String(buf,0,len);

System.out.println(ip+":"+text);

s.close();

ss.close(); 

}

}

 

Socket 的shutdownOutput();在发送文件结束后调用该方法,给对方机器一边对方机器结束读取循环。

 

Tcp传输最容易出现的问题

 

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

通过例程分析:

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

解决办法:

自定义结束标记

使用shutdownInput,shutdownOutput方法。

 

 

上传图片的设计案例:

 

(上传的任务)

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

public class UploadTask implements Runnable{

private static final int SIZE =1024*1024*2;

private Socket s;

public UploadTask(Socket s) {

this.s = s;

}

public void run() {

int count = 0;

String ip =s.getInetAddress().getHostAddress();

System.out.println(ip +".....connected");

try{

// 读取客户端发来的数据。

InputStream in = s.getInputStream();

// 将读取到数据存储到一个文件中。

File dir = new File("c:\\pic");

if (!dir.exists()) {

dir.mkdirs();

}

File file = new File(dir, ip +".jpg");

//如果文件已经存在于服务端 

while(file.exists()){

file = newFile(dir,ip+"("+(++count)+").jpg");

}

FileOutputStream fos = newFileOutputStream(file);

byte[] buf = new byte[1024];

int len = 0;

while ((len = in.read(buf)) != -1) {

fos.write(buf, 0, len);

if(file.length()>SIZE){

System.out.println(ip+"文件体积过大");

fos.close();

s.close();

 

System.out.println(ip+"...."+file.delete());

return ;

}

}

// 获取socket输出流,将上传成功字样发给客户端。

OutputStream out = s.getOutputStream();

out.write("上传成功".getBytes());

fos.close();

s.close();

}catch(IOException e){

}

}

}

(上传的客户端)

package cn.itcast.net.p1.uploadpic;

 

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

 

public class UploadPicClient {

public static void main(String[] args)throws UnknownHostException, IOException

{

//1,创建客户端socket。

Socket s = new Socket("192.168.1.100",10006);

//2,读取客户端要上传的图片文件。

FileInputStream fis = newFileInputStream("c:\\0.bmp");

//3,获取socket输出流,将读到图片数据发送给服务端。

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 lenIn = in.read(buf);

String text = new String(buf,0,lenIn);

System.out.println(text);

fis.close();

s.close();

}

}

(上传的服务端)

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

public class UploadPicServer {

public static void main(String[] args)throws IOException {

//创建tcp的socket服务端。

ServerSocket ss = new ServerSocket(10006);

while(true){

Socket s = ss.accept(); 

new Thread(new UploadTask(s)).start(); 

}

//获取客户端。

// ss.close();

}

}

 

浏览器客户端-自定义服务端

可以自定义一个服务器,用浏览器访问。

访问时,在地址栏输入http://IP地址:端口号  即可

在浏览器上面点击“查看”->“源代码”。可以查看浏览器解析前的数据。

小知识点:telnetwindows中的远程登陆命令,格式为:telnetIP 端口号   可以远程登录一台主机,并在dos命令行对主机进行命令式的配置。

 

 

URL-URLConnection)

URL(“浏览器链接地址栏中输入的全部内容”)

URL(协议,主机,port端口号,文件)

 

 

 

getProtocol() 获取此 URL 的协议名称。

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

getPort()  获取此 URL 的端口号。

getPath()  获取此 URL 的路径部分。

getFile()  获取此 URL 的文件名。

getQuery() 获取此 URL 的查询部分。

 

 URLConnection  openConnection()     返回一个URLConnection 对象,它表示到 URL 所引用的远程对象的连接. 每次调用该方法都会打开一个新的连接。

URLConnection 类其实是把Socket封装在了内部,所以他还有getInputStream()和getOutputStream()功能。

openStream()方法其实就是openConnection().getInputStream()的简写。

 

域名解析

当我们向服务器发送一个URL的时候,如果写的是主机名而不是IP地址的话,那么,就会先连接上DNS(域名解析服务器),根据名字找到对应的IP并返回给请求机,然后请求机才按照该IP地址去连接到相应的服务器。 此过程就是域名解析。

但域名解析时会先在自己主机上C:\WINDOWS\system32\drivers\etc\hosts找有没有相应的主机名,如果没有才会去DNS找。利用这个原理,可以将一些想要屏蔽的网站名字写入本地文件,让被屏蔽网站和本地默认IP127.0.0.1 对应。也可以将经常访问的网站名和对应的IP地址写入该文件,就可以省去连接DNS服务器的麻烦了,速度会更快。

C:\WINDOWS\system32\drivers\etc\hosts

127.0.0.1 对应的是本机主机名 localhost

 

URL程序举例:网页爬虫。

import java.io.*;

importjava.util.regex.*;

 

class Spider {

       publicstatic void main(String[] args) {

             

       }

       publicvoid getMail(){

              URLurl= new URL("");

              URLConnectionconn = url.openConnectiong();

              BufferedReaderbf = new BufferedReader(new InputStreamReader(conn.getInputStream()));

              Stringline = null;

              reg="\\m+@\\m+(\\.\\m+)+";

              Pattern p = Pattern.compile(reg);

              while((line=bf.readLine())!=-1){

                    

                     Matcherm = p.matches(line);

                     while(m.find()){

                            System.out.println(m.group());

                     }

              }

             

             

       }

}

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值