兼职做平面模特网站,服装市场调网站建设的目的,襄阳seo公司,陈塘庄网站建设本次学习Socket的编程开发#xff0c;该技术在一些通讯软件#xff0c;比如说微信#xff0c;QQ等有广泛应用。
网络结构
这些都是计算机网络中的内容#xff0c;我们在这里简单回顾一下#xff1a; UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission Contr…本次学习Socket的编程开发该技术在一些通讯软件比如说微信QQ等有广泛应用。
网络结构
这些都是计算机网络中的内容我们在这里简单回顾一下 UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission ControlProtocol):传输控制协议。 TCP协议 特点:面向连接、可靠通信。 TCP的最终目的:要保证在不可靠的信道上实现可靠的传输。 TCP主要有三个步骤实现可靠传输:三次握手建立连接传输数据进行确认四次挥手断开连接。 四次握手是为了确保收发数据都已完成。 我们首先了解一下关于获取主机地址的相关方法 //获取本机IP地址对象的地址InetAddress localHost InetAddress.getLocalHost();System.out.println(localHost.getHostName());System.out.println(localHost.getHostAddress());//获取指定IP域名的IP地址对象InetAddress ip InetAddress.getByName(www.baidu.com);System.out.println(ip.getHostName());//输出ip主机名称System.out.println(ip.getHostAddress());//输出指定域名的ip地址//判断6秒内能否与百度联通相当于pingSystem.out.println(ip.isReachable(6000));UDP通信开发
随后我们进行客户端与服务端的数据发送与接收 首先是客户端的定义 //创建客户端对象这里可以选择使用无参构造当然也可以指定端口进行有参构造在不指定端口时系统会默认分配DatagramSocket socket new DatagramSocket();//创建数据包封装对象存储数据信息
// public DatagramPacket(byte buf[], int offset, int length,
// InetAddress address, int port) {
// setData(buf, offset, length);
// setAddress(address);
// setPort(port);
// }byte[] bytes 客户端消息:我是鹏翔.getBytes();//客户端发送的数据包需要指明接收的服务端的IP地址以及端口DatagramPacket packet new DatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),8888);//发送数据包socket.send(packet);System.out.println(客户端数据发送完毕);socket.close();服务端的开发设计 System.out.println(服务端启动);//创建一个服务端对象并指定端口DatagramSocket socket new DatagramSocket(8888);//定义所能够接收的数据的大小byte[] buffer new byte[1024*64];//服务器接受的数据包DatagramPacket packet new DatagramPacket(buffer,buffer.length);//接收数据socket.receive(packet);int length packet.getLength();String string new String(packet.getData(), 0, length);//发送多少数据则接收多少数据System.out.println(string);socket.close();至此我们的客户端与服务端便开发完成了在实验中我们需要先启动服务端再启动客户端。 至此完成客户端与服务端的消息发送与接收。
UTP通信多发多收
但这只是完成了一次消息的发送与接收而在实际情况中我们往往需要进行多发多收那么该如何实现呢 客户端设计
public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建一个服务端对象并指定端口DatagramSocket socket new DatagramSocket(8888);//定义所能够接收的数据的大小byte[] buffer new byte[1024*64];//服务器接受的数据包DatagramPacket packet new DatagramPacket(buffer,buffer.length);while(true){socket.receive(packet);int length packet.getLength();String string new String(packet.getData(), 0, length);System.out.println(string);System.out.println(--------------------------);}}客户端设计
public static void main(String[] args) throws IOException {//创建客户端对象DatagramSocket socket new DatagramSocket();Scanner scannernew Scanner(System.in);while(true){System.out.println(请说:);String msg scanner.nextLine();if (exit.equals(msg)) {System.out.println(客户端数据发送完毕);socket.close();break;}byte[] bytes msg.getBytes();//客户端发送的数据包需要指明接收的服务端的IP地址以及端口DatagramPacket packet new DatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),8888);//发送数据包socket.send(packet);}此外服务器是否能够接收多个客户端发送的消息呢当然可以只需要将客户端程序设置为允许多开即可。 TCP通信开发 public ServerSocket(int port) 为服务端程序注册端口
public Socket accept()方法阻塞等待客户端的连接请求一旦与某个客户端成功连接则返回服务端这边的Socket对象。 客户端设计实现 Socket socket new Socket(127.0.0.1,8088);//从socket中获取一个字节输出流用于给服务端发送OutputStream outputStream socket.getOutputStream();//原本的字节输出流并不好用将其封装为高级的数据输出流DataOutputStream dataOutputStream new DataOutputStream(outputStream);//开始写数据dataOutputStream.writeUTF(我爱你);dataOutputStream.close();socket.close();服务端设计实现 System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(8088);//调用accept方法,等待客户端的连接请求Socket accept serverSocket.accept();//从socket的通信管道中得到一个字节输入流InputStream inputStream accept.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);//使用数据输入流读取客户端发送的数据String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);System.out.println(accept.getInetAddress());//输出发送客户端的IP地址dataInputStream.close();serverSocket.close();同样的我们只是完成一条消息的发送与接收那么该如何实现数据的多发多收呢
TCP通信多发多收
其实实现与UDP时的完全相同只需要一个循环即可。 全选要加入循环的语句按住CtrlAltT
多发多收服务端设计
public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(8088);//调用accept方法,等待客户端的连接请求Socket accept serverSocket.accept();//从socket的通信管道中得到一个字节输入流InputStream inputStream accept.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);//使用数据输入流读取客户端发送的数据while (true) {String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);System.out.println(accept.getInetAddress());//输出发送客户端的IP地址}}多发多收客户端设计 public static void main(String[] args) throws IOException {//创建Socket对象,并同时请求服务端程序的连接声明服务器的IP与端口号Socket socket new Socket(127.0.0.1,8088);//从socket中获取一个字节输出流用于给服务端发送OutputStream outputStream socket.getOutputStream();//原本的字节输出流并不好用将其封装为高级的数据输出流DataOutputStream dataOutputStream new DataOutputStream(outputStream);//开始写数据Scanner scanner new Scanner(System.in);while (true) {System.out.println(请输入内容:);String string scanner.nextLine();if (exit.equals(string)) {dataOutputStream.close();socket.close();System.out.println(退出成功);break;}dataOutputStream.writeUTF(string);dataOutputStream.flush();//将数据刷新出去防止数据还留在内存中}}同时需要注意TCP作为可靠连接一旦服务端挂掉了那么就会抛出异常 我们可以通过捕获抛出的异常来判断是否客户端退出。
public class Servers {public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(8088);//调用accept方法,等待客户端的连接请求Socket accept serverSocket.accept();//从socket的通信管道中得到一个字节输入流InputStream inputStream accept.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);//使用数据输入流读取客户端发送的数据while (true) {try {String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);} catch (IOException e) {System.out.println(accept.getInetAddress()客户端退出了);//输出发送客户端的IP地址dataInputStream.close();serverSocket.close();break;}}}
}TCP通信聊天室
如何实现一个服务器与多个客户端通信呢现在的肯定是不行的因为我们在判断客户端关闭后也将服务端关闭了事实上此时服务端只能和一个客户端建立可靠连接归根接地是因为在建立连接后服务端一直在等待某一个客户端发送的消息这就导致会停留在那从而无法与其他客户端建立连接。怎么办呢可以使用多线程来解决。 改进后的服务端
package IPAddress.TCP;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerMany {public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(8088);//调用accept方法,等待客户端的连接请求Socket accept null;while (true) {accept serverSocket.accept();new ServerReadThread(accept).start();}}
}多开线程实现服务端接收数据
package IPAddress.TCP;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;public class ServerReadThread extends Thread{private Socket socket;public ServerReadThread(Socket accept) {this.socketaccept;}Overridepublic void run() {try {InputStream inputStream socket.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);System.out.println(socket.getInetAddress()客户端上线了);//输出发送客户端的IP地址//使用数据输入流读取客户端发送的数据while (true) {try {String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);} catch (IOException e) {System.out.println(socket.getInetAddress()客户端下线了);dataInputStream.close();socket.close();break;}}} catch (IOException e) {System.out.println(服务异常 socket.getInetAddress() 连接中断);}}
} 最后我们可以通过一个聊天室的案例来简单检验一下成果 首先我们需要在服务端定义一个集合用于保存连接的socket同时由主线程负责创建socket连接一旦有新的客户端开启则开启一个新的子线程用于该客户端与服务端之间的通信
public class Server {public static ListSocket socketsnew ArrayList();public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(8088);//调用accept方法,等待客户端的连接请求Socket accept null;while (true) {accept serverSocket.accept();sockets.add(accept);new ServerReadThread(accept).start();}}
}在服务端的子线程中负责将接收的信息输出并将接收的信息转发给其他客户端端口转发
import java.io.*;
import java.net.Socket;public class ServerReadThread extends Thread{private Socket socket;public ServerReadThread(Socket accept) {this.socketaccept;}Overridepublic void run() {try {InputStream inputStream socket.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);System.out.println(socket.getInetAddress()客户端上线了哟);//输出发送客户端的IP地址//使用数据输入流读取客户端发送的数据while (true) {try {String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);sendMsg(string);} catch (IOException e) {System.out.println(socket.getInetAddress()客户端下线了);Server.sockets.remove(socket);dataInputStream.close();socket.close();break;}}} catch (IOException e) {System.out.println(服务异常 socket.getInetAddress() 连接中断);}}private void sendMsg(String string) throws IOException {//发送给所有Socket管道去接收System.out.println(转发数据);for (Socket online:Server.sockets) {OutputStream outputStream online.getOutputStream();DataOutputStream dataOutputStream new DataOutputStream(outputStream);dataOutputStream.writeUTF(string);dataOutputStream.flush();}}
}
在客户端设计中除了原本的输入数据发送信息外还要开启一个线程用于接收服务器转发的数据
public class Clients {public static void main(String[] args) throws IOException {//创建Socket对象,并同时请求服务端程序的连接声明服务器的IP与端口号Socket socket new Socket(127.0.0.1,8088);new ClientReadThread(socket).start();//从socket中获取一个字节输出流用于给服务端发送OutputStream outputStream socket.getOutputStream();//原本的字节输出流并不好用将其封装为高级的数据输出流DataOutputStream dataOutputStream new DataOutputStream(outputStream);//开始写数据Scanner scanner new Scanner(System.in);while (true) {System.out.println(请输入内容:);String string scanner.nextLine();if (exit.equals(string)) {dataOutputStream.close();socket.close();System.out.println(退出成功);break;}dataOutputStream.writeUTF(string);dataOutputStream.flush();//将数据刷新出去防止数据还留在内存中}}
}客户端接收转发信息的线程设计如下
public class ClientReadThread extends Thread{private Socket socket;public ClientReadThread(Socket accept) {this.socketaccept;}Overridepublic void run() {try {InputStream inputStream socket.getInputStream();//将原始的字节输入流包装成高级的数据输入流DataInputStream dataInputStream new DataInputStream(inputStream);//使用数据输入流读取客户端发送的数据while (true) {try {String string dataInputStream.readUTF();//通信很严格要保持一致System.out.println(string);} catch (IOException e) {System.out.println(自己客户端下线了);dataInputStream.close();socket.close();break;}}} catch (IOException e) {System.out.println(服务异常 socket.getInetAddress() 连接中断);}}
}BS架构通信开发
首先了解一下BS架构的基本原理 BS架构下我们并不需要开发客户端程序。只需要开发服务端即可
public class Server {public static ListSocket socketsnew ArrayList();public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(9090);while (true) {Socket accept serverSocket.accept();System.out.println(子线程启动);sockets.add(accept);new ServerReadThread(accept).start();}}
}随后进行服务端子进程的设计用于向浏览器响应一段文字注意要想向浏览器响应内容就需要遵循固定的HTTP协议规定即符合下面的要求 服务端子线程设计如下
public class ServerReadThread extends Thread{private Socket socket;public ServerReadThread(Socket accept) {this.socketaccept;}Overridepublic void run() {try {System.out.println(上线访问了);OutputStream outputStream socket.getOutputStream();//将原始的字节输出流包装成高级的打印流PrintStream printStream new PrintStream(outputStream);printStream.println(HTTP/1.1 200 OK);printStream.println(Content-Type:text/html;charsetUTF-8);printStream.println();printStream.println(div stylecolor:red;font-size:40px;text-align:center服务端响应/div);printStream.close();socket.close();} catch (IOException e) {System.out.println(服务异常 socket.getInetAddress() 连接中断);}}
}前面的BS架构设计中每当浏览器发起一次访问就会创建一个线程然而当我们的网站访问量十分大时即面对一些高并发情况就会出现宕机现象。对于这种情况可以通过线程池来进行优化。 在主线程中设计一个线程池来控制线程数量
public class Server {public static ListSocket socketsnew ArrayList();public static void main(String[] args) throws IOException {System.out.println(服务端启动);//创建ServerSocket对象并指明端口号方便接收客户端数据ServerSocket serverSocket new ServerSocket(9090);//通过线程池来控制执行线程的数量与任务队列数量ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor(16 * 2, 16 * 2,0, TimeUnit.SECONDS, new ArrayBlockingQueue(8),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());while (true) {Socket accept serverSocket.accept();System.out.println(子线程启动);threadPoolExecutor.execute(new ServerReadRunnable(accept));}}
}将原本的线程改造为任务。
public class ServerReadRunnable implements Runnable{private Socket socket;public ServerReadRunnable(Socket accept) {this.socketaccept;}Overridepublic void run() {try {System.out.println(上线访问了);OutputStream outputStream socket.getOutputStream();//将原始的字节输出流包装成高级的打印流PrintStream printStream new PrintStream(outputStream);printStream.println(HTTP/1.1 200 OK);printStream.println(Content-Type:text/html;charsetUTF-8);printStream.println();printStream.println(div stylecolor:red;font-size:40px;text-align:center服务端响应/div);printStream.close();socket.close();} catch (IOException e) {System.out.println(服务异常 socket.getInetAddress() 连接中断);}}
}