JavaSocket编程——通信是这样进行的在编程中,Socket是用的最多的。像大家熟悉的QQ、MSN,都是用到了Socket相关的技术。让我们一起揭开Socket的神秘面纱。Socket编程一、网络基础(指计算机网络)计算机网络部分可以参考相关博客:《TCP/IP协议栈与OSI参考模型详解》http://wangdy.blog.51cto.com/3845563/15883791,两台计算机之间通讯需要满足以下三个条件:IP地址、协议、端口号2、TCP/IP协议:是目前世界上使用最广泛的协议,是多种协议的集合在TCP和IP的不同层次上,也成为TCP/IP协议族,或TCP/IP协议栈:TCP/IP网络层:数据链路层:物理层:网线、双绞线、网卡等。4.IP地址为了实现网络中不同计算机之间的通信,每台计算机都必须有一个唯一的标识——IP地址32位二进制5.端口区分一台主机的多个不同应用,端口号范围为0-65535,其中0-1023为预留为系统编辑。如:HTTP:80FTP:21Telnet:23IP地址+端口号构成所谓的Socket,Socket是网络上运行的程序之间双向通信链路的端点,是TCP和UDP6.0的基础。Socket套接字:将网络上唯一标识的IP地址和端口组合起来,形成一个唯一可标识的标识套接字。Socket原理机制:通信的两端都有Socket。网络通信其实就是两个Socket之间通过IO传输实现Socket之间的通信数据。7.Java中的网络支持针对不同层次的网络通信,Java提供了不同的API。提供了四种网络函数:InetAddress:用于标识网络上的硬件资源,主要是IP地址URL:UniformResourceLocator,通过它可以直接读取或写入网络上的数据Sockets:使用TCP协议实现的网络通信Socket相关类Datagram:使用UDP协议,将数据存储在用户数据报中,通过网络进行通信。二、InetAddressInetAddress类用于标识网络上的硬件资源和标识网际协议(IP)地址。该类无构造方法//获取本地InetAddress实例InetAddressaddress=InetAddress.getLocalHost();address.getHostName();//获取计算机名address.getHostAddress();//获取IP地址byte[]bytes=地址。getAddress();//获取字节数组形式的IP地址,四部分以点分隔//获取其他主机的InetAddress实例InetAddressaddress2=InetAddress.getByName("Otherhostname");InetAddressaddress3=InetAddress.getByName("IP地址");3.URL类//创建一个URL实例URLbaidu=newURL("http://www.baidu.com");URLurl=newURL(baidu,"/index.html?username=tom#test");//?表示参数,#表示锚点url.getProtocol();//获取协议url.getHost();//获取主机url.getPort();//如果不指定端口号,则根据默认端口不同的协议。此时getPort()方法的返回值为-1url.getPath();//获取文件路径url.getFile();//文件名,包括文件路径+参数url.getRef();//相对路径为锚点,即#号后的内容url.getQuery();//查询字符串,即参数2.利用URL读取网页内容。通过URL对象的openStream()方法可以获取指定资源的输入流,可以使用该流读取或访问网页上的资源//使用URL读取网页内容//创建一个URL实例URLurl=newURL("http://www.baidu.com");InputStreamis=url.openStream();//通过openStream方法获取资源的字节输入流。InputStreamReaderisr=newInputStreamReader(is,"UTF-8");//将字节输入流转换为字符输入流。如果不指定编码,中文可能会出现乱码BufferedReaderbr=newBufferedReader(isr);//给字符输入流添加一个缓冲区,提高读取效率Stringdata=br.readLine();//读取数据while(data!=null){System.out.println(data);//输出数据data=br.readerLine();}br.close();isr.colose();is.close();四、TCP编程1.TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手建立连接形成传输数据的通道,传输大连接中数据量大,效率会略低3、Socket通信步骤①创建ServerSocket和Socket②打开Socket连接的输入/输出流③根据协议读/写Socket④关闭输入和输出流并关闭Socket4.服务器端:①创建一个ServerSocket对象,绑定它设置监听端口②通过accept()方法监听客户端请求③连接建立后,读取客户端发送的请求信息通过输入流④通过输出流到客户端发送本地口音信息⑤关闭相关资源/***基于TCP协议的Socket通信实现用户登录,服务器*///1.创建服务端Socket,即ServerSocket,指定绑定端口,监听此端口ServerSocketserverSocket=newServerSocket(10086);//1024-65535的某个端口//2.调用accept()方法开始监听,等待客户端的连接Socketsocket=serverSocket.accept();//3.获取输入流并读取Client信息System.out.println("我是服务器,客户端说:"+info);}socket.shutdownInput();//关闭输入流//4、获取输出流,响应客户端的请求OutputStreamos=socket.getOutputStream();PrintWriterpw=newPrintWriter(os);pw.write("Welcome!");pw.flush();//5.关闭资源pw.close();os.close();br.close();isr.close();is.close();socket.close();serverSocket.close();5、客户端:①创建一个Socket对象,指定要连接的服务器的地址和端口号②连接建立后,通过输出流连接到服务器发送请求信息③通过输入流获取服务器响应信息④关闭responseresource//Client//1、创建客户端Socket,指定服务器地址和端口Socketsocket=newSocket("localhost",10086);//2、获取Output流,向服务器发送信息OutputStreamos=socket.getOutputStream();//字节输出流PrintWriterpw=newPrintWriter(os);//将输出流打包成打印流pw.write("用户名:admin;密码:123");pw.flush();socket.shutdownOutput();//3.获取输入流,从服务器读取响应信息.out.println("我是客户端,服务端说:"+info);}//4、关闭资源br.close();is.close();pw.close();os.close();套接字关闭();6、应用多线程实现服务端与多个客户端的通信①服务端创建ServerSocket,循环调用accept()等待客户端连接②客户端创建socket请求连接服务端③服务端接受硬读请求,并创建socket与客户端建立专线连接④建立连接的两个socket在单独的线程中通话⑤服务端继续等待新的连接//服务端线程处理//socketSocketsocket=null与本线程相关;//publicserverThread(Socketsocket){this.socket=socket;}publicvoidrun(){//服务器处理代码}//===============================================//服务器代码ServerSocketserverSocket=newServerSocket(10086);Socketsocket=null;intcount=0;//记录客户端数量while(true){socket=serverScoket.accept();ServerThreadserverThread=newServerThread(socket);serverThread.start();count++;System.out.println("客户端连接数:"+count);}5.UDP编程UDP协议(UserDatagramProtocol)是无连接的,不可靠、无序、快速的数据传输,首先将要传输的数据定义为数据报(Datagram),大小限制为64k,并在数据报中指定数据需要到达的Socket(主机地址和端口号)。然后将数据报发送出去DatagramPacket类:表示数据报包DatagramSocket类:用于端到端通信的类1、服务器端实现步骤①创建DatagramSocket,指定端口号②创建DatagramPacket③接受发送的数据信息client④读取Data//Server端,基于UDP//1实现用户登录。在服务器端创建一个DatagramSocket,指定端口DatagramSocketsocket=newdatagramSocket(10010);//2。创建一个数据报,接受客户端发送的数据byte[]data=newbyte[1024];//DatagramPacketpacket=newDatagramPacket(data,data.length);//3.接受客户端发送的数据socket.receive(packet);//该方法在接收数据报之前会一直阻塞//4.读取数据Stringinfo=newString(data,o,data.length);System.out.println("我是服务器,客户端告诉我"+info);//=============================================================//给Client响应数据//1、定义client地址,端口号,dataInetAddressaddress=packet.getAddress();intport=packet.getPort();byte[]data2="Welcome!".geyBytes();//2.创建包含响应数据信息的数据报DatagramPacketpacket2=newDatagramPacket(data2,data2.length,address,port);//3.响应客户端socket.send(packet2);//4.关闭资源socket.close();2、客户端实现步骤①定义发送信息②创建DatagramPacket,包括要发送的信息③创建DatagramSocket④发送数据//Client//1、定义服务器地址、端口号、数据InetAddressaddress=InetAddress.getByName("localhost");intport=10010;byte[]data="用户名:admin;密码:123".getBytes();//2.创建数据报,包括发送的数据信息DatagramPacketpacket=newDatagramPacket(data,data,length,address,port);//3.创建一个DatagramSocket对象DatagramSocketsocket=newDatagramSocket();//4.向服务器发送数据socket.send(packet);//接受服务器端响应数据//========================================//1。创建数据报接受服务器端响应数据byte[]data2=newbyte[1024];DatagramPacketpacket2=newDatagramPacket(data2,data2.length);//2、接受服务器端响应数据socket.receive(packet2);Stringraply=newString(data2,0,packet2.getLenth());System.out.println("我是客户端,服务端说:"+reply);//4.关闭资源socket.close();6、注意事项:1、多线程的优先级:根据实际经验,适当降低优先级,否则可能会出现程序运行效率低的情况2、是否关闭输出流和输入流:对于同一个socket,如果输出流关闭,与输出流关联的套接字也将关闭关闭,所以一般不需要关闭流,直接关闭socket即可3.使用TCP通信传输对象,IO中的序列化部分4.socket编程传输文件,IO流部分
