Socket编程
作者:互联网
文章目录
一、Socketbc编程
public class ServerSocket
extends Object
implements Closeable
这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。
服务器套接字的实际工作由SocketImpl类的实例执行。 应用程序可以更改创建套接字实现的套接字工厂,以配置自己创建适合本地防火墙的套接字。
1.IP和端口号(组成网络)
IP(internet Protocol),网络之间的互联协议,IP(加子网掩码)是区分不同计算机的唯一标识
端口号是计算机的逻辑通信接口,不同的应用程序用不同的端口号,网络应用程序的区分标识
端口号一般是两个字节(16给bit 65536)
1、公认端口
第一类:公认端口(Well Known Ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议,例如:80端口实际上总是HTTP通讯。 21 ftp 22 ssh(security shell) 443 https …
2、注册端口 (1024-49151)
第一类:公认端口(Well Known Ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议,例如:80端口实际上总是HTTP通讯。 21 ftp 22 ssh(security shell) 443 https …
3、动态和、私有端口
第三类:动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口
2.Tcp与UDP概念
网络七层协议: 网络层,数据链路层,网络层ip,传输层,会话层,表示层,应用层
传输层两个重要协议
TCP(Transmission Control Protocol)连通性
传输控制协议,提供可靠无差错的数据传输,保证数据正确性,速度慢,占用系统资源高,TCP面向连接。每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
UDP(User Datagram Protocol)()
用户数据报协议,不可靠的数据传输,可能丢包,速度快,占用资源较少,UDP面向无连接。UDP支持一对一,一对多,多对一和多对多的交互通信。
3.Socket编程原理
服务器端
(1) 创建ServerSocket对象,绑定监听端口;
(2) 通过accept()方法监听客户端请求(产生阻塞);
(3) 连接建立后,通过输入流读取客户端发送的请求信息;
(4) 通过输出流向客户端发送相应信息;
(5) 关闭相应资源。
客户端
(1)创建Socket对象,指明需要连接的服务器地址和端口;
(2)连接建立后,通过输出流向服务器端发送请求信息;
(3)通过输入流获取服务器端返回的响应信息;
(4)关闭相应资源;
4.代码
/**
* @author zhangyifan
* @version 8.0
* @description:服务器
* @date 2021/12/7 9:56
*/
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket= null;
Socket socket=null;
BufferedReader bufferedReader=null;
PrintWriter printWriter=null;
try {
// (1) 创建ServerSocket对象,绑定监听端口;
serverSocket = new ServerSocket(16666);
System.out.println("服务器以准备就绪,等待连接");
// (2) 通过accept()方法监听客户端请求(产生阻塞);
socket= serverSocket.accept();//监听
//按行读取提高效率 需要把字节流转换成字符流
bufferedReader=//BufferedReader在字符流套接缓存,提高读写效率
new BufferedReader( //InputStreamReader吧字节流转字符流
new InputStreamReader( socket.getInputStream()) ) ;
//按行读取客户端信息
String s = bufferedReader.readLine();
//打印
System.out.println("客户端说"+s);
// (4) 通过输出流向客户端发送相应信息;
printWriter =new PrintWriter(socket.getOutputStream());
//写入信息
printWriter.println("你好客户端 收到了信息"+s+",给你回复");
//清空管道
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (printWriter!=null){
printWriter.close();
}
if (bufferedReader!=null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket!=null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* @author zhangyifan
* @version 8.0
* @description:客户端
* @date 2021/12/7 10:35
*/
public class Client {
public static void main(String[] args) {
Socket socket= null;
PrintWriter printWriter=null;
BufferedReader bufferedReader=null;
try {
// (1) 创建Socket对象,指明需要连接的服务器地址和端口;
socket = new Socket("192.168.41.26",16666);
// (2) 连接建立后,通过输出流向服务器端发送请求信息;
printWriter=new PrintWriter(socket.getOutputStream());
//写入消息
printWriter.println("你好服务器");
//写入消息
printWriter.flush();
// (3) 通过输入流获取服务器端返回的响应信息;
bufferedReader=
new BufferedReader(new InputStreamReader(socket.getInputStream()));
//按行读取信息
String s = bufferedReader.readLine();
//打印
System.out.println("服务器说"+s);
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭资源
if (bufferedReader!=null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (printWriter!=null){
printWriter.close();
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
持续通话
有问题的代 码 发送消息有时会不及时
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 14:19
*/
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
BufferedReader bufferedReader=null;
PrintWriter printWriter=null;
/* (1) 创建ServerSocket对象,绑定监听端口;
(2) 通过accept()方法监听客户端请求(产生阻塞);
(3) 连接建立后,通过输入流读取客户端发送的请求信息;
(4) 通过输出流向客户端发送相应信息;
(5) 关闭相应资源。*/
try {
// (1) 创建ServerSocket对象,绑定监听端口;
serverSocket=new ServerSocket(16666);
System.out.println("服务器准备就绪+等待客户端连接");
// (2) 通过accept()方法监听客户端请求(产生阻塞);
socket=serverSocket.accept();
// (3) 连接建立后,通过输入流读取客户端发送的请求信息;
bufferedReader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
//(4) 通过输出流向客户端发送相应信息;
printWriter=new PrintWriter(socket.getOutputStream());
Scanner scanner=new Scanner(System.in);
while (true){
//读取客户端·
String clientMsg = bufferedReader.readLine();
System.out.println("客户端说"+clientMsg);
//包含
if (clientMsg.contains("借钱")){
printWriter.println("你被啦黑了");//写出
printWriter.flush();//刷新
break;
}
//提示
System.out.println("请输入:");
//阻塞并等待控制台输入
String serverinputMsg = scanner.next();
//写入信息
printWriter.println(serverinputMsg);
//刷新
printWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// (5) 关闭相应资源。
if(printWriter!=null){
printWriter.close();
}
try {
if(bufferedReader!=null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(socket!=null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(serverSocket!=null){
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 14:19
*/
public class Client {
public static void main(String[] args) {
Socket sOcket=null;
PrintWriter printWriter=null;
BufferedReader bufferedReader=null;
// (1)创建Socket对象,指明需要连接的服务器地址和端口;
try {
sOcket=new Socket("192.168.41.26",16666);
//(2)连接建立后,通过输出流向服务器端发送请求信息;
printWriter =new PrintWriter(sOcket.getOutputStream());
//(3)通过输入流获取服务器端返回的响应信息;
bufferedReader=
new BufferedReader(new InputStreamReader(sOcket.getInputStream()));
Scanner scanner=new Scanner(System.in);
while (true){
System.out.println("请输入:");
String clientInputMsg = scanner.next();
printWriter.println(clientInputMsg);
printWriter.flush();
String ServerMSG=bufferedReader.readLine();
System.out.println("服务器说"+ServerMSG);
if (ServerMSG.contains("拉黑")){
printWriter.println("别慌,拉黑前借钱");
printWriter.flush();//刷新
break;//退出
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// (4) 关闭相应资源。
try {
if(bufferedReader!=null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(printWriter!=null){
printWriter.close();
}
try {
if(sOcket!=null){
sOcket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
多线程持续通话 可创建多个Client并 但是信息发送必须有去有回否则Server不知道下一个发给谁
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 15:11
*/
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket=null;
try {
serverSocket=new ServerSocket(16666);
while (true){
System.out.println("服务端已经准备就绪,等待客户端连接。。。。");
//等待客户端连接
Socket accept = serverSocket.accept();
new Thread(new MTServer(accept)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 15:11
*/
public class MTServer implements Runnable{
private Socket socket;
//赋值
public MTServer(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//提示
System.out.println("客户端"+Thread.currentThread().getName()+"已经连接,可以对话");
BufferedReader bufferedReader=null;
PrintWriter printWriter=null;
try {//转换
bufferedReader=
new BufferedReader(new InputStreamReader(socket.getInputStream()));
//发送
printWriter=new PrintWriter(socket.getOutputStream());
Scanner scanner=new Scanner(System.in);
while (true){
String clientMsg = bufferedReader.readLine();
//打印
System.out.println("客户端"+clientMsg);
//阻塞并等待控制台输入
System.out.println("请求输入");
String serverInputMsg = scanner.next();
//写入信息
printWriter.println(serverInputMsg);
//刷新管道
printWriter.flush();
if (clientMsg.contains("借钱")){
printWriter.println("你被拉黑了");
printWriter.flush();//刷新
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// (5) 关闭相应资源。
if (printWriter != null) {
printWriter.close();
}
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 15:11
*/
public class Client {
public static void main(String[] args) {
Socket socket=null;
PrintWriter printWriter=null;
BufferedReader bufferedReader=null;
try {
socket=new Socket("192.168.41.26",16666);
printWriter =new PrintWriter(socket.getOutputStream());
bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
/*printWriter.println(bufferedReader.readLine());*/
Scanner scanner=new Scanner(System.in);
while(true){
System.out.println("请输入");
//获取
String next = scanner.next();
//发出
printWriter.println(next);
//刷新
printWriter.flush();
//行读取
String s = bufferedReader.readLine();
System.out.println("服务器说"+s);
if (s.contains("拉黑")){
printWriter.println("别慌,拉黑前借钱");
printWriter.flush();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// (4) 关闭相应资源。
try {
if(bufferedReader!=null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(printWriter!=null){
printWriter.close();
}
try {
if(socket!=null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.UDP程序的原理
服务器端
- 创建服务端DatagramSocket类
- 准备数据 以字节数组的形式
- 打包 DatagramPacket+客户端的地址和端口
- 发送
- 释放资源
客户端
- 创建客户端 DatagramSocket 类 + 指定的接收端口
- 准备接收数据的容器 以字节数组的形式封装为DatagramPacket
- 包 接收数据
- 分析 (组装字节数组)
- 释放资源
6.主要类的方法
DatagramSocket类 要用于实现信息的发送和接收
public DatagramSocket() | 构造DatagramSocket对象,不指定监听的端口 |
---|---|
public DatagramSocket(int port) | 构造DatagramSocket对象,同时指定监听的端口 |
public void send (DatagramPacket p) | 发送数据报 |
public void receive(DatagramPacket p) | 接收数据报 |
DatagramPacket类用于包装需要发送或接收的信息
ublic DatagramPacket(byte[] buf,int length) | 用来接收长度为length的数据包,length测试必须小于等于buf。length |
---|---|
public DatagramPacket(byte[] buf,int length,InetAddressaddress,int port) | 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号 |
public byte[] getData() | 返回接收数据 |
public intgetLength() | 返回要发送或者接收数据的长度 |
7、代码具体实现
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 11:36
*/
public class Client {
public static void main(String[] args) {
DatagramSocket datagramSocket=null;
try {
//1创建连接
datagramSocket=new DatagramSocket(18888);
// 2准备接受容器 设置大小
byte[] tempBytes=new byte[1024];
DatagramPacket datagramPacket=new DatagramPacket(tempBytes,1024);
//3、包接受信息
System.out.println("客户端准备就绪,等待服务器");
datagramSocket.receive(datagramPacket);
//4 分析 组装字节数组
String s = new String(tempBytes, 0, datagramPacket.getLength());
System.out.println("收到信息"+s);
} catch ( Exception e) {
e.printStackTrace();
}finally {
if (datagramSocket!=null){
datagramSocket.close();
}
}
}
}
/**
* @author zhangyifan
* @version 8.0
* @description:
* @date 2021/12/7 11:36
*/
public class Server {
public static void main(String[] args) {
DatagramSocket datagramSocket=null;
try {
//创建服务端 DatagramSocket类
datagramSocket=new DatagramSocket();
//准备数据 字节
String str="hello client";
byte[] sendMsgBytes=str.getBytes();//装字节
//1、 发送消息的字节数组 2.发送消息字节数组的长度 3.ip 4 端口号
DatagramPacket datagramPacket=
new DatagramPacket(sendMsgBytes
, sendMsgBytes.length
, InetAddress.getByName("localhost")
,18888);
//发送
datagramSocket.send(datagramPacket);
System.out.println("消息发送完毕");
} catch ( Exception e) {
e.printStackTrace();
}finally {
//释放资源
if (datagramSocket!=null){
datagramSocket.close();
}
}
}
}
注意事项:先启动客户端,receive方法在接收到数据报前一直阻塞。再运行服务器端。
8、UDP对聊
总结
标签:printWriter,Socket,编程,bufferedReader,println,new,null,socket 来源: https://blog.csdn.net/qq_45438019/article/details/121761055