黑马程序员-Socket网络编程
来源:互联网 发布:java发送自定义短信 编辑:程序博客网 时间:2024/05/22 08:27
---------------------- 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) 地址
staticInetAddress getLocalHost():获取本机的IP地址对象,返回一个InetAddress对象
String getHostAddress():获取 IP地址字符串,返回String类型
String getHostName():获取此 IP地址的主机名,返回String类型
staticInetAddress 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通讯
不同的协议用不同的socket
UDP协议: 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>();@Overridepublic 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 stubSocket 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 网络编程
- 黑马程序员--网络编程Socket
- 黑马程序员--网络编程Socket
- 黑马程序员-Socket网络编程
- 黑马程序员---网络编程(socket编程)
- 黑马程序员--网络编程Socket(udp)
- 黑马程序员-Socket网络编程一点心得
- 黑马程序员_java中的网络编程Socket
- 黑马程序员_java之Socket网络编程
- 黑马程序员 Socket网络编程--聊天室
- 黑马程序员——网络编程(Socket)
- 黑马程序员_90_网络编程Socket
- 黑马程序员----------Java网络编程(Socket编程)笔记
- 黑马程序员——网络编程(Socket编程)
- 黑马程序员——网络编程(Socket编程)下
- 黑马程序员——Socket网络编程聊天室
- 黑马程序员 关于Socket编程 网络聊天的总结
- 黑马程序员——Java---Socket网络编程原理
- Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离
- [基础语法]1.NSObject的几个方法
- centos 修改主机名
- 微软面试题及答案
- 正向代理 与 反向代理
- 黑马程序员-Socket网络编程
- IOS开发 REST请求 ASIHTTPRequest用法
- myeclipse配置hadoop开发环境,及遇到问题解决
- 不重复抽奖
- Linux下用java 调用 C类库实战 视频
- 链表在c中的应用
- Android Logcat
- l138地址-TI支持
- Android ADT 无法在线安装,离线下载ADT压缩包方法。SDK Manager无法更新