黑马程序员_网络编程(一)

来源:互联网 发布:十年前错过了淘宝语录 编辑:程序博客网 时间:2024/05/12 07:39
---------------------- javaEE+Android开发、java培训、期待与您交流! ----------------------
网络编程概述:
java也可以完成网络通信的过程,利用java语言可以实现网络之间的通信,不再是前面所学习的单机版的通行。
网络通信的模型:
               ①找到将要通信的IP
               ②数据发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数组进行标识,为方便称呼这个数字为“端口”(0-65535,通常0-1024被系统端口所占用),即使逻辑上的端口
               ③两者之间要进行通信,需要定义通讯规则,则这个通讯规则成为协议,最常见国际组织定义了一个通用的协议为:TCP/IP协议(如果通信两端的协议不相同,则不能互相通信),还有TCP和UDP协议
IP地址的组成:用于标识网络中设备的标识,由4个字节组成,后8位为地址段。本机地址为:127.0.0.1,可用主机名(可以使用该地址来检查网卡  ping 127.0.0.1),为了便于操作IP地址,将IP地址封装成为一个个对象,InetAdress可以将IP封装成为一个对象(InetAdress s=InetAdress.getByName(127.0.0.1(可以传入主机名)));
static getLocalHost():得到本机地址
getHostAdress():返回IP地址字符串
getHostAdress():返回主机名

传输协议:
UDP(单向连接):
①面向无连接,就是发送数据的时候无需建立链接,将数据打包成为数据包发送到指定的地址和端口,如果接收端存在,则接收到数据,否则丢失掉数据。
②由于是面向无连接的,所以不需建立连接,速度快。
③数据会被封包,每个数据包不超过64k,
④因为在是无连接的,在传送数据时会丢包,所以是不可靠传输
例子:聊天,网络视频会议都只是讲求速度,数据丢失不会造成影响。
TCP(双连接):
①面相连接,必须保证传输双方都建立好连接,形成传输数据的通道
②在连接中进行大数量的传输,没有数据量的限定
③通过三次握手协议完成连接,是可靠的协议
④必须建立连接,效率会很低
三次握手协议:以客户端和服务器端为例:客户端向服务器端发送连接请求为第一次,服务器端响应连接为第二次,客户端响应服务器端为第三次连接
例子:下载,打电话,需要双方建立连接才能进行通话。
Socket
什么是socket?
①Socket就是为网络服务提供的一种机制
②通信的两端都有Socket才能实现通信
③数据在两个Socket之间通过IP进行传输
socket中文为套接口,有些地方也成为插座。那要怎么理解socket呢?
从系统的外部来看,套接口可以说是网络程序的应用编程接口,通过套接口,应用程序能访问到相关的网络服务。
从应用层(或者说从应用进程)的角度来看,套接口就是通信的端点,通过这个通信端点,进程之间可以进行通信,而不必关心数据的传输的细节。
从源程序的角度看,一个套接口就是让应用能从网络读/写数据的一个文件描述符。应用进程彼此间的通信,是通过读/写套接口描述符实现的。网络通信的过程就是由数据的发送者将要发送的信息写入一个套接口,再通过中间环节将信息传输到接收端的套接口中,然后就可以由接收端的应用程序将信息从套接口中取出。


UDP传输:

DatagramSocket:表示用来发送和接收数据报的套接字
发送:send(Datagrampaket p)
接收:receive(Datagramepaket p)
UDP数据发送实例步骤
       ①建立UDPSocket服务②提供数据,将数据封装到数据包中③通过Socket服务的发送功能将数据包发送出去,④操作底层资源,需关闭
接收到也是同样的操作,只是接收到不需要只需要指定接收来自那个端口的数据即可,
实例源代码:

数据发送端

package cn.itheima.Socket;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.InetSocketAddress;public class UDPClientSocket {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stub//建立数据发送套接字DatagramSocket ds = new DatagramSocket();//将数据打成包byte [] buf = "黑马程序员".getBytes();DatagramPacket dp = new DatagramPacket(buf,buf.length, InetAddress.getByName("127.0.0.1"),1000);//同过发送套接字进行数据发送ds.send(dp);System.out.println("数据发送端、、、");//关闭套接字ds.close();}}


数据接收端:

package cn.itheima.Socket;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;public class UDPserverSocket {/** * @param args * @throws Exception */public static void main(String[] args) throws Exception {// TODO Auto-generated method stub//接收来端的端口号DatagramSocket ds = new DatagramSocket(1001); while(true){byte[] buf = new byte [1024];DatagramPacket dp = new DatagramPacket(buf, buf.length);ds.receive(dp);System.out.println("数据接收端。。。。。");System.out.println(new String(buf,0,buf.length));//接收端接收数据,一直打开,不需要关闭} }}

发送端可以不指定监听端口,有默认监听端口,如果想要接收端能获取到不同的数据来源,这里可以使用键盘输入,将键盘输入的数据再封装成为数据包,按照上面的方式发送出去就可以了。
注意:这里的read是阻塞方法,接收不到数据,将会在这里阻塞,不会进行循环,也就是不必考虑死循环的问题。
上面的的程序要开启两个窗口,则需要开启两个进程来执行,现在要使用多线程的思想来编写代码,使其能实现同时接收数据的功能。
下面是自己搞的一个程序:该程序就可以简单地实现聊天的功能,可以接收和发送数据,只需将端口号改变一下,你就可以和任何人聊天,发送端和接收端都在同一个程序中,涉及多线程。
分析步骤:①建立UDPSocket断点服务
                  ②创建数据包,用来将要传输的数据进行封装,接收端也要使用DatagramePaket来解析得到的数据
                  ③Socket接收和发送
                  ④判断调节,不满足条件就关闭资源

package cn.itheima.Socket;import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;public class UDPClientSocket {/** * 需求:一个进程里有多个线程,用来接收和发送数据 * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubaDatagramSocket ds = new DatagramSocket();DatagramSocket dsrec = new DatagramSocket(10003);new Thread(new Send(ds)).start();new Thread(new Recv(dsrec)).start();}}class Send implements Runnable{DatagramSocket ds = null;BufferedReader br =null;Send(DatagramSocket ds){this.ds=ds;}@Overridepublic void run() {// TODO Auto-generated method stub//键盘输入并传输br = new BufferedReader(new InputStreamReader(System.in));String line = null;while(true){try {if(!("over".equals(line = br.readLine()))){DatagramPacket dp = new DatagramPacket(line.getBytes(),line.getBytes().length,InetAddress.getByName("127.0.0.1"), 10002);ds.send(dp);System.out.println("发送的数据位:"+line);}else{ds.close();break;}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class Recv implements Runnable{DatagramSocket ds = null;Recv(DatagramSocket ds ){this.ds=ds;}@Overridepublic void run() {System.out.println("接收数据");// TODO Auto-generated method stubbyte [] buf = new byte[1024];while(true){DatagramPacket dp = new DatagramPacket(buf, buf.length);try {//System.out.println("lsdkjflskdjf");ds.receive(dp);System.out.println("10003收到的数据:"+new String(dp.getData(),0,dp.getLength()));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}


TCP传输:
概述:Tcp传输和UDP传输不相同,TCP的传输与接收时分开的,不像UDP的接收和发送融为一体,TCP分为客户端和服务端。客户端和服务器端是通过通道来进行连接的。
Socket():客服端通过Socket()创建未连接套接字,通过connect方法来指定目的地。
ServerSocket();
TCP传输客户端建立的过程:
                                        ①Socket对象,建议一创建该对象就明确目的地;
                                        ②如果建立连接成功,说明数据传输通道已建立
                                        ③使用流(Socket流,网络IO流,该流既能读又能写,底层建立好的。想要获取该流,可以通过Socket对象得到该流(getOutputStream,getInputStream)。传输的为字节流)进行数据传输
                                        ④关闭资源
TCP传输服务器端建立过程:①创建Socket服务,通过ServerSocket创建服务端点
                                               ②服务端向外提供一个端口
                                               ③获取链接过来的客服端对象(ss.accept(s))
                                               ④通过客服端对象获取Socket流,读取客服端发来的数据,并进行操作
                                                ⑤关闭资源(关闭链接过来的客服端和服务器端)
通过一个实例说明:

客户端实例

package cn.itheima.Socket;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;public class TcpClientDemo {/** * 从键盘录入数据,发送到服务器端,有服务器端返回大写 * @param args * @throws Exception */public static void main(String[] args) throws Exception {// TODO Auto-generated method stub//创建客户端服务端点Socket s = new Socket("127.0.0.1",10001);//Socket流的获取,并将其封装到字符缓冲区中BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//从键盘录入,并将其加入缓冲区中BufferedReader b =new BufferedReader(new InputStreamReader(System.in));while(true){String line = b.readLine();if(!("over".equals(line))){bw.write(line);//由于在读取的时候readLine不会读取回车换行符,所以在服务器端就读取不到换行符,不会返回结果bw.newLine();//将数据缓冲刷新到Socket流中bw.flush();}else{s.close();return;}//将Socket输入流加载进缓冲区,BufferedReader br =new BufferedReader(new InputStreamReader(s.getInputStream()));String len =br.readLine();System.out.println("返回的大写为:"+len);}}}


服务器端实例:

package cn.itheima.Socket;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.ServerSocket;import java.net.Socket;public class TcpServerDemo {/**要求:客服端想服务器端发送数据,服务器端将数据装换为大写后 * 再将数据返回客户端,可以一直接收,接收 一行就转换一行并返回 * * @param args * @throws Exception */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubOutputStream os=null;ServerSocket ss = new ServerSocket(10001);Socket s = ss.accept(); BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); String line = null; while((line = br.readLine())!=null){ if("over".equals(line)){ break; } System.out.println("接收到来自客户端的:"+line); line=line.toUpperCase(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); bw.write(line); bw.newLine(); bw.flush(); } }}

这里会出现这样一个现象,客服端和服务端都在莫名的等待,原因是客服端和服务器端都有阻塞式的方法,这些方法没有读到结束标识,都会一直等,导致都没有结果输出。
还有就是在客户端关闭Socket流的时候,并没有判断关闭服务器端的服务,但是服务器端自动关闭,原因是在客户端关闭服务的时候,会在Socket流中写入一个-1,也就是结束标记,readLine底层是read原理,读到-1,自动结束。
类似的,也可以在客户端写入数据,传到服务器端,服务器端将数据存储在文件夹里,只是加入IO流技术,是很容易实现的。


---------------------- javaEE+Android开发、java培训、期待与您交流! ----------------------
0 0
原创粉丝点击