您的位置:首页 > 理论基础 > 计算机网络

黑马程序员——java学习14(毕23-24)——网络编程

2015-08-12 19:19 1271 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1、



UDP

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

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

  因无连接,是不可靠协议

  不需要建立连接,速度快

TCP

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

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

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

  必须建立连接,效率低

Socket

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

  通信的两端都有Socket

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

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

IP地址

  网络中设备的标识

  不易记忆,可用主机名

  本地回环地址:127.0.0.1,主机名:localhost

端口号

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

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

传输协议

  通讯的规则

  常见协议TCP,UDP

2、IP地址

package learn;

import java.io.IOException;
import java.net.InetAddress;

public class IPDemo {
public static void main(String[] args) throws IOException{
//        InetAddress i = InetAddress.getLocalHost();
//        System.out.println(i.toString());
//        System.out.println("address:"+i.getHostAddress());
//        System.out.println("name"+i.getHostName());
//任意一台注意提取地址
InetAddress ia = InetAddress.getByName("192.168.1.103");
System.out.println("address:"+ia.getHostAddress());
System.out.println("name"+ia.getHostName());
}
}


运行结果



3、UDP

3.1、UDP发送接收

3.1.1、UDP发送

package learn;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.*;

/*
* 通过UDP传输方式将一段文字数据发送出去
* 思路
* 1、建立udpsocket服务
* 2、提供数据,并将数据封装带数据包中
* 3、通过socket服务的发送功能,将数据包发送出去
* 4、关闭资源
* */

public class UdpSend {
public static void main(String[] args) throws Exception{
//1、创建udp服务。通过DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//2、确定数据,封装数据包
byte[] buf="udplaile".getBytes();
//处理数据的地址,端口
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10000);
//3、通过socket服务,将已有的数据包发送出去,通过send方法
ds.send(dp);
//4、关闭资源
ds.close();

}
}


3.1.2、UDP接收

package learn;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/*需求:定义一个应用程序,用于接收UDP协议传输的数据并处理的
* 定义接收端
* 思路
* 1、定义Udpsocket服务,通常会监听一个端口,其实就是给这个接受网络应用程序定义数字标识
* 方便与明确哪些数据过来该应用程序可以处理
* 2、定义一个数据包。因为要存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息
* 3、通过socket服务的receive方法将受到的数据存入已定义好的数据包中
* 4、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
* 5、关闭资源
*
* */
public class UdpRece {
public static void main(String[] args) throws Exception{
//1、创建udpsocket,建立端点
DatagramSocket ds = new DatagramSocket(10000);
//2、定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3、通过服务的receive方法将收到的数据存入数据包中
ds.receive(dp);
//4、通过数据包的方法获取其中的数据
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();
}
}


3.2、模拟chat

package learn;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//发送端
class Send implements Runnable
{
//用哪个socket不确定,故构造时传指定Socket
private DatagramSocket ds;
//构造函数,用于接收Socket对象
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)
{
if("886".equals(line))
break;
//字符串转字节数组
byte[] buf = line.getBytes();
//字节数组存入数据包,定义要发送的主机和端口号
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10002);
//数据包丢入socket
ds.send(dp);

}
//关闭发送
ds.close();
}
catch(Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}
//接收端
class Rece implements Runnable
{
private DatagramSocket ds;
//构造函数,用于接收Socket对象
Rece(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
try
{
//接收端做好随时接收的准备,故无限循环
while(true)
{
//                将接收到的数据存储到定义好的数据包中
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//数据包丢入socket服务中
ds.receive(dp);
//获取数据中主机地址和数据长度
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
//输出数据
System.out.println(ip+".."+data);
}
}
catch(Exception e)
{
throw new RuntimeException("接收端失败");
}
}
}
public class ChatDemo {
public static void main(String[] args) throws Exception {
//先有Socket
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10002);
//线程启动
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}


4、TCP

4.1、端点接收数据,打印在控制台

客户端
通过查阅socket对象,发现在该对象建立时就可以连接指定的主机,
因为tcp是面向连接的,所以在建立socket服务时就要有服务端存在并连接成功,形成通路后再该通道进行数据的传输
步骤
* 1、创建socket服务,并指定要连接的主机和端口
* 2、获取输出流,并发送
* 3、关闭服务
* */

*服务端:

步骤
* 1、建立服务端的socket服务,ServerSocket();
* 2、获取连接过来的客户端对象
* 通过ServerSocket的accept方法,没有连接就会等,所以这个方法阻塞式的
* 3、客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据
* 并打印在控制台
* 4、关闭服务端(可选)

package learn;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

class Tcpclient
{
public static void main(String[] args) throws IOException{
//创建客户端的socket服务,指定目的主机和端口
Socket s = new Socket("192.168.1.103",10003);
//为了发送数据,应该选取socket流中的输出流
OutputStream out = s.getOutputStream();
out.write("tcp ge men laile".getBytes());
s.close();
}
}

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

* */
class Server
{
public static void main(String[] args)throws IOException {
//建立服务端的socket服务,并监听一个端口
ServerSocket ss = new ServerSocket(1003);
//通过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();
ss.close();
}
}


4.1.1、TCP上传文件

客户端
* 1、服务端点
* 2、读取客户端已有的图片数据
* 3、通过socket输出流将数据发给服务端
* 4、读取服务端反馈信息
* 5、关闭

服务器端
* 这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程
* 这时B客户端连接,只有等待
* 因为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法,所以暂时获取不到B客户端对象
* 那么为了可以让多个客户端同时并发访问服务器
* 那么服务端最好就是将每个客户端封装到一个担负的线程中,这样就可以同时处理多个客户端请求
*
* 如何定义线程
* 只要明确了每一个客户端要在服务端执行的代码即可,将该代码存入run方法中

4.2、TCP并发上传图片

package learn2;
/*
* tcp并发上传图片
*/
import java.io.*;
import java.net.*;
//客户端
class  PicClient
{
public static void main(String[] args)throws Exception
{
//args为传入的文件的路径
if(args.length!=1)
{
System.out.println("请选择一个jpg格式的图片");
return ;
}

//dos命令行中传入的路径
File file = new File(args[0]);
//判断文件是否存在和是否是文件
if(!(file.exists() && file.isFile()))
{
System.out.println("该文件有问题,要么不存在,要么不是文件");
return ;

}
//判断是否是jpg图片
if(!file.getName().endsWith(".jpg"))
{
System.out.println("图片格式错误,请重新选择");
return ;
}
//过5M的图片都不要
if(file.length()>1024*1024*5)
{
System.out.println("文件过大。。。没安好心。");
return ;
}

//创建Socket流
Socket s = new Socket("192.168.1.3",10008);

//建立读取流,读取图片文件
FileInputStream fis = new FileInputStream(file);
//建立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 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;
//获取客户端的IP地址
String ip  = s.getInetAddress().getHostAddress();
try
{
//打印连接上的客户端的IP地址
System.out.println(ip+"-------连接");
InputStream in = s.getInputStream();
File dir =  new File("e:\\Tcp传输图片");
File file = new File(dir,ip+"("+(count)+")"+".jpg");
//如果要存入的名称已经存在了那么就把count自增,再设置新的名字。
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(10008);

while(true)
{
//获取连接到服务端的客户端对象
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
//一直处于接收状态,所以不关闭资源
//ss.close();
}
}


5、URL

是一个浏览器地址封装类

URI范围比URL大

常用方法

    String getFile() :获取此 URL 的文件名。
String getHost() :获取此 URL 的主机名(如果适用)。
String getPath() :获取此 URL 的路径部分。
int getPort() :获取此 URL 的端口号。
String getProtocol() :获取此 URL 的协议名称。
String getQuery() :获取此 URL 的查询部

6、小知识

InetSocketAddress类封装的是(IP地址+端口)

ServerSocket(int port, int backlog)

backlog队列的最大长度,一般50

7、域名解析

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: