黑马程序员-Socket网络编程
2013-11-12 00:05
393 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
(2):通信端口
(3):通信协议
Ip地址:ip地址实际上是有4个字节共32位的二进制来表示的,但是这样不便于记忆,那么把这32位分割成4分,每一字节8位,再转成十进制表示。2^8=256-1,范围在0~255,255是广播地址
分A,B,C类IP地址
子网掩码的作用:为了标识网络号
示例:255.255.255.0
A类IP地址:1个网络号+3个主机号
B类IP地址:2个网络号+2个主机号
C类IP地址:3个网络号+1个主机号
地址
static
InetAddress getLocalHost():获取本机的IP地址对象,返回一个InetAddress对象
String getHostAddress():获取 IP
地址字符串,返回String类型
String getHostName():获取此 IP
地址的主机名,返回String类型
static
InetAddress getByName(String host):在给定主机名的情况下确定主机的 IP
地址。主机名可以是机器名(如 "
地址的文本表示形式(如"192.168.10.10")
注意:主机名有可能重复,但IP地址是唯一的(在同一网内),所以此方法推荐使用IP地址
boolean isReachable(int timeout):
测试是否可以达到该地址(能否在指定时间内连接上该地址),timeout
为调用中止前的时间(以毫秒为单位)
static InetAddress[]
getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回其 IP
地址所组成的数组。
用法:getAllByName(“www.baidu.com”),一个域名可以对应多个主机,百度域名可能有多个(主机)服务器,所以这个方法是得到百度的所有服务器的IP地址对象
UDP协议: DatagramSocket(发送与接收),
DatagramPacket(数据包)
UDP没有客户端与服务端之分
发送端与接收端都用DatagramSocket
TCP协议:Socket(客户端),
ServerSocket(服务端)
TCP分客户端,服务端,两者有各自的Socket
•
将数据及源和目的封装成数据包中,不需要建立连接
•
每个数据报的大小在限制在64k内
•
因无连接,是不可靠协议,会出现丢包(带宽或CPU能力不足)
•
不需要建立连接,速度快(效率比tcp高)
TCP
•
建立连接,形成传输数据的通道。
•
在连接中进行大数据量传输,数据没有大小限制
•
通过三次握手完成连接,是可靠协议
•
必须先建立连接,效率会稍低
创建UDP发送端
思路与步骤:
1:定义Socket服务(DatagramSocket)
DatagramSocket(int port) //如果没有指定端口,那么由CPU指定
创建数据报套接字并将其绑定到本地主机上的指定端口。
2:定义一个数据包,封装需要发送的数据
DatagramPacket(byte[] buf, intlength, InetAddress address, int port)
构造数据报包,用来将长度为length
的包发送到指定主机上的指定端口号。
3:通过Socket服务发送信息
send(DatagramPacket p)
从此套接字发送数据报包。
4:关闭资源
close()
核心代码:
创建一个UDP接收端
思路与步骤
1:创建一个Socket服务
DatagramSocket(int port)
创建数据报套接字并将其绑定到要监听(要接收数据的)的指定端口。
2:定义一个数据包,用于存储到接收到的数据
DatagramPacket(byte[] buf, intlength)
构造DatagramPacket,用来接收长度为 length
的数据包。
3:通过Socket服务的receive()将接收到的数据存放到数据包中
receive(DatagramPacket p)
从此套接字接收数据报包。
4:通过数据包特有的方法获取接收到的数据
5:关闭资源
核心代码:
创建一个TCP的客户端
思路与步骤:
1:创建客户端Socket服务,指定要连接的主机地址和服务端口
2:为了发送数据,应该获取Socket流中的输出流
3:往输出流写数据(与UDP这一步骤有区别,不需要写发送数据的语句,只需把数据写入流即可)
4:关闭Socket流对象
核心代码
创建一个TCP服务端
思路与步骤:
1:建立一个服务端socket的服务,并监听一个端口
2:通过accept方法获取连接过来的客户端的对象
3:获取客户端发过来的数据,要使用客户端对象的读取流来读取
4:断开连着的客户端,免得占用资源
核心代码
建立TCP客户端与服务端互访:
客户端发送数据到服务端,服务端接收到数据后,返回自定义数据
客户端代码:
服务端代码:
在建立TCP客户端与服务端互访的时候,有如下细节需要注意
(1) 客户端在写入数据之后,需要刷新,才能被发送
(2) 服务端在读数据的时候,使用的是缓冲读取流,readLine()判断数据结束的标记是回车符\r\n,所以要在客户端发送数据后再添加一个换行:newLine();
(3) 同理,服务端发送返回数据的时候,也要刷新和换行:newLine();
介绍一个新的带自动刷新的输出流对象:PrintWrite
并且PrintWrite的特有输出方法println()能够自动加上换行符
那么上述代码核心部分
BufferedWriterbufOut =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
修改为:PrintWriter out = newPrintWriter(s.getOutputStream(),true);
bufOut.write(line.toUpperCase());
bufOut.newLine();
bufOut.flush();
修改为:out.println(line.toUpperCase());
客户端从服务端下载文件
服务端支持多台主机同时连接下载,并统计被下载多少次,同一IP地址下载多次算一次
服务端代码示例:
客户端代码:
客户端往服务端上传文件
要注意的地方:要注意结束标记,服务端读取的结束标记,否则会一直阻塞
可以用Socket的方法,shutDownOutput()关闭客户端的输出流,执行此方法是通知服务端,文件读完了,可以结束服务端读取的循环
问题:为什么客户端从服务端下载文件的时候,不需要shutDownOutput()也可以正常执行?
答:
下载:服务端使用自定义输入流读取需要被下载的文件,然后交给socket输出流,当输入流读到流末尾的时候会自动结束读取循环,socket输出流没有写入结束符号。但是服务端会继续往下执行,会关闭socket对象,如果socket被关闭,客户端会收到通知,会自动结束客户端的socket流
上传:因为客户端用自定义的输入流中读取需要被上传的文件,交给socket的输出流,自定义的输入流读完数据会结束读取,但是不会写入结束符号,会结束while循环,继续往下执行,会关闭socket,服务端从socket读取数据的时候,也不会读到结束符号,所以服务端会一直等待,这时候必须要客户端发送一个结束的标记,提示服务端结束读取。
URLConnection(重点)属于应用层
URL url = new URL(www.baidu.com:8080/web/demo.html);
URLConnection conn= url.openConnection();
//此时openConnection()方法会返回一个URLConnection类型的对象
该对象的作用是把Socket封装在了内部,起的是Socket的连接作用
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
网络通信的三要素:
(1):IP地址(2):通信端口
(3):通信协议
Ip地址:ip地址实际上是有4个字节共32位的二进制来表示的,但是这样不便于记忆,那么把这32位分割成4分,每一字节8位,再转成十进制表示。2^8=256-1,范围在0~255,255是广播地址
分A,B,C类IP地址
子网掩码的作用:为了标识网络号
示例:255.255.255.0
A类IP地址:1个网络号+3个主机号
B类IP地址:2个网络号+2个主机号
C类IP地址:3个网络号+1个主机号
类 InetAddress
此类表示互联网协议 (IP)地址
static
InetAddress getLocalHost():获取本机的IP地址对象,返回一个InetAddress对象
String getHostAddress():获取 IP
地址字符串,返回String类型
String getHostName():获取此 IP
地址的主机名,返回String类型
static
InetAddress getByName(String host):在给定主机名的情况下确定主机的 IP
地址。主机名可以是机器名(如 "
java.sun.com"),也可以是其 IP
地址的文本表示形式(如"192.168.10.10")
注意:主机名有可能重复,但IP地址是唯一的(在同一网内),所以此方法推荐使用IP地址
boolean isReachable(int timeout):
测试是否可以达到该地址(能否在指定时间内连接上该地址),timeout
为调用中止前的时间(以毫秒为单位)
static InetAddress[]
getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回其 IP
地址所组成的数组。
用法:getAllByName(“www.baidu.com”),一个域名可以对应多个主机,百度域名可能有多个(主机)服务器,所以这个方法是得到百度的所有服务器的IP地址对象
网络通讯也叫Socket通讯
不同的协议用不同的socketUDP协议: DatagramSocket(发送与接收),
DatagramPacket(数据包)
UDP没有客户端与服务端之分
发送端与接收端都用DatagramSocket
TCP协议:Socket(客户端),
ServerSocket(服务端)
TCP分客户端,服务端,两者有各自的Socket
UDP协议与TCP协议的区别
UDP•
将数据及源和目的封装成数据包中,不需要建立连接
•
每个数据报的大小在限制在64k内
•
因无连接,是不可靠协议,会出现丢包(带宽或CPU能力不足)
•
不需要建立连接,速度快(效率比tcp高)
TCP
•
建立连接,形成传输数据的通道。
•
在连接中进行大数据量传输,数据没有大小限制
•
通过三次握手完成连接,是可靠协议
•
必须先建立连接,效率会稍低
创建UDP发送端
思路与步骤:
1:定义Socket服务(DatagramSocket)
DatagramSocket(int port) //如果没有指定端口,那么由CPU指定
创建数据报套接字并将其绑定到本地主机上的指定端口。
2:定义一个数据包,封装需要发送的数据
DatagramPacket(byte[] buf, intlength, InetAddress address, int port)
构造数据报包,用来将长度为length
的包发送到指定主机上的指定端口号。
3:通过Socket服务发送信息
send(DatagramPacket p)
从此套接字发送数据报包。
4:关闭资源
close()
核心代码:
DatagramSocket ds = new DatagramSocket(8888); byte[] buf = "我的信息".getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.10.10"),10000); ds.send(dp); ds.close();
创建一个UDP接收端
思路与步骤
1:创建一个Socket服务
DatagramSocket(int port)
创建数据报套接字并将其绑定到要监听(要接收数据的)的指定端口。
2:定义一个数据包,用于存储到接收到的数据
DatagramPacket(byte[] buf, intlength)
构造DatagramPacket,用来接收长度为 length
的数据包。
3:通过Socket服务的receive()将接收到的数据存放到数据包中
receive(DatagramPacket p)
从此套接字接收数据报包。
4:通过数据包特有的方法获取接收到的数据
5:关闭资源
核心代码:
DatagramSocket ds = new DatagramSocket(10000); 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()); int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); ds.close();
创建一个TCP的客户端
思路与步骤:
1:创建客户端Socket服务,指定要连接的主机地址和服务端口
2:为了发送数据,应该获取Socket流中的输出流
3:往输出流写数据(与UDP这一步骤有区别,不需要写发送数据的语句,只需把数据写入流即可)
4:关闭Socket流对象
核心代码
Socket s = new Socket("192.168.1.254",10003); //创建客户端Socket服务,指定要连接的主机地址和服务端口 OutputStream out = s.getOutputStream(); //为了发送数据,应该获取Socket流中的输出流 out.write("我是服务端".getBytes()); //往输出流写数据 s.close(); //关闭流
创建一个TCP服务端
思路与步骤:
1:建立一个服务端socket的服务,并监听一个端口
2:通过accept方法获取连接过来的客户端的对象
3:获取客户端发过来的数据,要使用客户端对象的读取流来读取
4:断开连着的客户端,免得占用资源
核心代码
ServerSocket ss = new ServerSocket(10003); //通过accept方法获取连接过来的客户端的对象 Socket s = ss.accept();//accept()返回的是一个Socket类型的对象 String ip = s.getInetAddress().getHostAddress(); System.out.println(ip); //获取客户端发过来的数据,要使用客户端对象的读取流来读取 InputStream in = s.getInputStream();//得到客户端对象后,获取读取流 byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); s.close();//断开连着的客户端,免得占用资源
建立TCP客户端与服务端互访:
客户端发送数据到服务端,服务端接收到数据后,返回自定义数据
客户端代码:
class TransClient { public static void main(String[] args) throws Exception { 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())); //定义一个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(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())); String line = null; while((line=bufIn.readLine())!=null) { System.out.println(line); bufOut.write(line.toUpperCase()); bufOut.newLine(); bufOut.flush(); } s.close(); ss.close(); } }
在建立TCP客户端与服务端互访的时候,有如下细节需要注意
(1) 客户端在写入数据之后,需要刷新,才能被发送
(2) 服务端在读数据的时候,使用的是缓冲读取流,readLine()判断数据结束的标记是回车符\r\n,所以要在客户端发送数据后再添加一个换行:newLine();
(3) 同理,服务端发送返回数据的时候,也要刷新和换行:newLine();
介绍一个新的带自动刷新的输出流对象:PrintWrite
并且PrintWrite的特有输出方法println()能够自动加上换行符
那么上述代码核心部分
BufferedWriterbufOut =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
修改为:PrintWriter out = newPrintWriter(s.getOutputStream(),true);
bufOut.write(line.toUpperCase());
bufOut.newLine();
bufOut.flush();
修改为:out.println(line.toUpperCase());
客户端从服务端下载文件
服务端支持多台主机同时连接下载,并统计被下载多少次,同一IP地址下载多次算一次
服务端代码示例:
public class MyServer { public static void main(String[] args) throws Exception { @SuppressWarnings("resource") ServerSocket server = new ServerSocket(10000); ClientThread ct = null; while (true) { Socket client = server.accept(); //accept()是阻塞式方法,如果有连接,才会往下执行 ct = new ClientThread(client);//注意多线程的写法 Thread t = new Thread(ct); t.start(); } } } class ClientThread extends Thread { private Socket client; public static int num = 0; public ClientThread(Socket client) { this.client = client; } HashSet<InetAddress> hashset = new HashSet<InetAddress>(); @Override public void run() { FileInputStream in = null; try { OutputStream out = client.getOutputStream(); in = new FileInputStream(new File("d:\\test\\IMG_0309.JPG")); byte[] buf = new byte[1024]; int len = 0; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); out.flush(); } if (!(hashset.contains(client.getInetAddress()))) { num++; } System.out.println("下载了" + num + "次"); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } } }
客户端代码:
public class DownloadPic { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub Socket socket = new Socket("192.168.10.10", 10000); InputStream in = socket.getInputStream(); FileOutputStream fos = new FileOutputStream(new File( "d:\\test\\我下载的pic.jpg")); byte[] buf = new byte[1024]; int length = 0; while ((length = in.read(buf)) != -1) { fos.write(buf, 0, length); fos.flush(); } fos.close(); socket.close(); } }
客户端往服务端上传文件
要注意的地方:要注意结束标记,服务端读取的结束标记,否则会一直阻塞
可以用Socket的方法,shutDownOutput()关闭客户端的输出流,执行此方法是通知服务端,文件读完了,可以结束服务端读取的循环
问题:为什么客户端从服务端下载文件的时候,不需要shutDownOutput()也可以正常执行?
答:
下载:服务端使用自定义输入流读取需要被下载的文件,然后交给socket输出流,当输入流读到流末尾的时候会自动结束读取循环,socket输出流没有写入结束符号。但是服务端会继续往下执行,会关闭socket对象,如果socket被关闭,客户端会收到通知,会自动结束客户端的socket流
上传:因为客户端用自定义的输入流中读取需要被上传的文件,交给socket的输出流,自定义的输入流读完数据会结束读取,但是不会写入结束符号,会结束while循环,继续往下执行,会关闭socket,服务端从socket读取数据的时候,也不会读到结束符号,所以服务端会一直等待,这时候必须要客户端发送一个结束的标记,提示服务端结束读取。
URLConnection(重点)属于应用层
URL url = new URL(www.baidu.com:8080/web/demo.html);
URLConnection conn= url.openConnection();
//此时openConnection()方法会返回一个URLConnection类型的对象
该对象的作用是把Socket封装在了内部,起的是Socket的连接作用
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net
相关文章推荐
- 黑马程序员第六季——网络(Socket编程)
- 黑马程序员----------Java网络编程(Socket编程)笔记
- 黑马程序员-java网络编程基础——socket编程基础
- 黑马程序员---.NET高级之网络套接字(Socket)编程
- [黑马程序员九]:Socket网络编程
- 黑马程序员_学习笔记:15) 网络编程:Socket(udp、tcp)
- 黑马程序员——网络概念及Socket编程示例
- 黑马程序员--网络编程Socket
- 黑马程序员---网络编程(socket编程)
- 黑马程序员—Socket 网络编程有感
- 黑马程序员————网络Socket编程
- 黑马程序员--10.网络编程--02.【网络传输三要素在Java中的体现】【TCP和UDP概念】【Socket基本概念】
- 黑马程序员--Java网络编程(InetAddress、DatagramSocket、DatagramPacket)
- 【黑马程序员】黑马入学准备篇:网络编程之 TCP、UDP和Socket综合实例
- 黑马程序员--Java基础学习之网络编程(TCP、UDP、Socket、模拟发送和接收数据)
- 黑马程序员 关于Socket编程 网络聊天的总结
- 黑马程序员——Java---Socket网络编程原理
- 黑马程序员 Socket网络编程--聊天室
- 黑马程序员——java基础——Socket网络编程
- 黑马程序员_Java学习日记20_Socket编程2