Socket网络编程_suck编程-程序员宅基地

技术标签: java  JAVASE  socket  网络通信  

Socket

1 环境查看

  1. 通过cmd窗口的命令:ipconfig查看本机IP地址
    查看IP地址
  2. 查看网络情况是否正常:ping百度官网
    查看网络情况

用来进行本地测试的地址 127.0.0.1,回环测试地址,默认代表的就是本机的IP

2 Socket概述

socket编程也叫套接字编程,应用程序可以通过它发送或者接受数据,可对其像打开文件一样打开/关闭/读写等操作.
套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.
网络套接字是IP地址与端口号TCP协议的组合
Socket就是为网络编程提供的一种机制,通信的两端都有Socket
网络通信其实就是Socket之间的通信,数据在两个Socket之间通过I/O进行传输.

通信模式
TCP网络通信模型

3 服务器端

3.1 ServerSocket

在服务器端选择一个端口号,在指定端口上等待客户端发起连接

构造方法:
ServerSocket(int port) 创建绑定到特定端口的服务器套接字
常用方法:
Socket accept() 侦听并接收到此套接字的连接
void close() 关闭此套接字
启动服务:
ServerSocket ss = new ServerSocket(端口号);
等待客户端发起连接,连接后会建立起通道:Socket socket = ss.accept();

4 客户端Socket

我们经常使用的就是客户端

构造方法:
Socket(String host,int port) 创建一个流套接字,并将其连接到指定主机上的指定端口号
常用方法:
InputStream getInputStream() 返回此套接字的输入流
OutputStream getOutputStream() 返回此套接字的输出流
void close() 关闭此套接字
新建Socket对象,连接指定IP指定的端口
Socket s = new Socket(IP,port);
从Socket获取双向的流:
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

5 入门案例

5.1服务器端代码编写

需求: 服务器端接收客户端发来的数据”hello”,并且给客户端响应数据”world”

创建包: cn.tedu.net
创建类: Server.java

package cn.tedu.net;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**本类用来表示Socket网络编程案例的服务器端
 * 完成步骤分析:
 * 1.启动服务器
 * 2.接收客户端的连接请求
 * 3.接收客户端发来的数据
 * */
/**测试注意事项:先启动服务器端,再启动客户端*/
public class Server {
    
	public static void main(String[] args) throws Exception {
    
		//1.启动服务器,指定端口号为8888,等待客户端的连接
		/**注意:
		 * 1.使用ServerSocket需要导包java.net.ServerSocket
		 * 2.此操作会抛出异常
		 * 3.指定的端口号范围是:0-655535,而0-1024是系统端口号,不能指定
		 * */
		ServerSocket ss = new ServerSocket(8888);
		//2.接收客户端的连接请求,并建立数据通信通道
		Socket socket = ss.accept();
		//3.获取到读取流,接收并读取客户端发来的数据
		InputStream in = socket.getInputStream();
		//通过循环挨个读取显示读到的内容
		for(int i = 0;i < 5;i++) {
    
			//int b = in.read();//此方法读取的结果是把字符转成数字
			char c = (char) in.read();//为了直接显示读取到的字符,需要强制类型转换(大转小,int转char)
			System.out.print(c);//print()同行输出,注意细节哦
		}
		//5.给客户端发送数据
		OutputStream out = socket.getOutputStream();
		out.write("world".getBytes());
		out.flush();
		
		//4.释放资源
		/**注意关流的顺序,后出现的先关闭*/
		in.close();
		ss.close();
	}
}

5.2 客户端代码编写

创建包: cn.tedu.net
创建类: Client.java

package cn.tedu.net;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**本类用来表示Socket网络编程案例的客户端
 * 完成步骤分析:
 * 1.指定要连接的服务器
 * 2.给服务器发送hello
 * */
public class Client {
    
	public static void main(String[] args) throws Exception {
    
		//1.指定要连接的服务器,需要同时指定服务器的IP & Port
		/**注意:
		 * 1.使用Socket需要导包java.net.Socket
		 * 2.此操作会抛出异常
		 * 3.如果使用的是本机的IP,地址是固定值,用来测试时使用127.0.0.1
		 * */
		Socket socket = new Socket("127.0.0.1",8888);
		//2.给服务器端发送hello
		OutputStream out = socket.getOutputStream();
		//把要输出的数据hello字符串转变成byte[]的形式进行输出
		out.write("hello".getBytes());
		out.flush();
		
		//4.读取从服务器端返回的数据
		InputStream in = socket.getInputStream();
		for (int i = 0; i < 5; i++) {
    
			char c = (char) in.read();//为了显示字符而不是数字,强制类型转换成char
			System.out.print(c);//不换行展示获取到的数据
		}
		
		//3.释放资源
		//out.close();
		socket.close();
		
	}
}

5.3 测试注意事项:

1.测试顺序:先启动服务器端,再启动客户端
2.可以打开多个控制台显示窗口,方便查看
3.可以将其中一个控制台显示窗口固定,否则多个窗口的显示内容是一样的
4.注意每次测试完毕后,都需要将之前的控制台窗口都关闭后再次进行新一轮的测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:要先启动服务器端再启动客户端,否则会报错,如下所示:

在这里插入图片描述

注意,下次测试的时候,把上次测试的窗口都关掉,重复启动多次,正在使用,新次测试就无法使用

在这里插入图片描述

6 服务器端线程模型

入门案例中,存在两种阻塞状态:

  1. 服务器端的accept()一直在等待客户端的连接
  2. 通信中的read()死等数据
    在这里插入图片描述

7 读一行写一行案例

创建包: cn.tedu.net
创建类: TestIO.java

package cn.tedu.net;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

/**这个类用来测试一行一行读取,一行一行写出*/
public class TestIO {
    
	public static void main(String[] args) {
    
		//method();//初步测试readLine()
		method2();//改进
	}
	public static void method2() {
    
		BufferedReader in = null;
		PrintWriter out = null;
		try {
    
			//1.读取一行数据,先拿到读取数据的流,注意文件需要自己在win创建
			in = new BufferedReader(new FileReader("D:\\b.txt"));
			//2.定义变量,记录每行读取到的数据
			String line;
			//3.设置循环读取数据,只要有数据就一直读取
			while( (line=in.readLine()) != null) {
    
				System.out.println(line);
			}
			
			//4.一行行写出数据:PrintWriter
			out = new PrintWriter(new FileWriter("D:\\b.txt"));
			out.println("java");
			out.println("hello");
			out.flush();//为了防止有数据没有发送过去,可以刷一下
		} catch (Exception e) {
    
			e.printStackTrace();
		}finally {
    
			try {
    
				//5.释放资源
				out.close();
				in.close();
			} catch (IOException e) {
    
				e.printStackTrace();
			}
		}
	}
	public static void method() {
    
		try {
    
			//1.读取一行数据,先拿到读取数据的流,注意文件需要自己在win创建
			BufferedReader in = new BufferedReader(new FileReader("D:\\b.txt"));
			//2.调用readLine方法进行测试
			String line = in.readLine();
			String line2 = in.readLine();
			String line3 = in.readLine();
			//测试1:b.txt没有数据时,readLine()返回null
			//测试2:b.txt有数据,而且是1整行数据,readLine()可以返回整行全部数据
			//测试3:b.txt有数据,而且是多行数据,readLine()只可以返回第1行全部数据
			/**原因:readLine()在读取数据时,会读取特殊标记,换行符\r\n,读到换行符就结束
			 * 结论:readLine()只可以读取1整行数据,如果是多行数据,需要多次调用
			 * */
			//3.打印测试结果
			System.out.println(line);
			System.out.println(line2);
			System.out.println(line3);
		} catch (Exception e) {
    
			e.printStackTrace();
		}
	}
}

8 拓展 : 回声案例

需求:接收客户端输入的每行数据,服务器再把回应给到用户

8.1 服务器端

接收客户端输入的每行数据,服务器再把回应给到用户

创建包: cn.tedu.net
创建类: Server2.java

package cn.tedu.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**这个类用来当做回声案例的服务器端
 * 1.启动服务器
 * 2.接收客户端的连接请求
 * 3.给每个用户分配对应的话务员
 * 4.话务员:主要负责和对应的客户端对象进行沟通I/O
 * */
/**1.创建优化后的Server2类,充当服务器端*/
public class Server2 {
    
	/**2.创建方法,负责服务多个客户*/
	public void service() {
    
		/**3.匿名对象+匿名内部类(重写run方法)*/
		new Thread() {
    
			/**5.把业务写在run()中*/
			@Override
			public void run() {
    
				try {
    
					//5.1 启动服务器,设置端口号为8000并等待客户端连接
					ServerSocket ss = new ServerSocket(8000);
					System.out.println("服务器启动成功!");
					while(true) {
    //死循环,一直accept,也就是接受客户端的连接请求
						//5.2 一直接受所有客户端的连接请求
						Socket socket = ss.accept();
						System.out.println("客户端连接成功!");
						//5.3 给每个客户分配自己对应的话务员,1v1
						HuaWuThread t = new HuaWuThread(socket);
						t.start();
					}
				} catch (IOException e) {
    
					e.printStackTrace();
				}
				
			};
		}.start();/**4.启动线程*/
	}
	
	/**6.创建话务员内部类,主要负责和客户端沟通 I/O*/
	class HuaWuThread extends Thread{
    
		//6.1 定义本类中的成员变量socket,用来保持通话
		Socket socket;
		//6.2含参构造,接受当前的连接信息,保持通话,为谁服务就保存谁的数据
		public HuaWuThread(Socket socket) {
    
			this.socket = socket;
		}
		//6.3把话务员的业务放在run(),一直读取客户端发来的数据,并作出回应
		@Override
		public void run() {
    
			try {
    
				//7.1读取一行BufferedReader,并且写出一行PrintWriter --双向流
				BufferedReader in = new BufferedReader(
						new InputStreamReader(socket.getInputStream()));
				PrintWriter out = new PrintWriter(
						new OutputStreamWriter(socket.getOutputStream()));
				//7.2读取客户端发来的一行数据
				String line;//定义变量,记录读取到的一行数据
				while((line = in.readLine()) != null) {
    //只要有数据就一直读
					System.out.println("客户端发来的数据:"+line);
					//7.1可以给客户端作出响应-接收键盘输入的响应
					System.out.println("请输入您的回应:");
					String input = new Scanner(System.in).nextLine();
					//7.2发出作为服务器的响应
					out.println(input);
					out.flush();//把数据刷出去
				}
			} catch (Exception e) {
    
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
    
		Server2 s = new Server2();
		s.service();
	}
}

8.2 客户端

接收客户端输入的每行数据,服务器再把回应给到用户

创建包: cn.tedu.net
创建类:Client2.java

package cn.tedu.net;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**本类用来做回声案例的客户端
 * 1.连接指定的服务器
 * 2.给服务器发送数据
 * 3.接收服务器响应的数据
 * */
public class Client2 {
    
	public static void main(String[] args) {
    
		try {
    
			//1.连接指定的服务器,同时指定服务器的IP和端口号
			Socket socket = new Socket("127.0.0.1",8000);
			//2.给服务器发送数据
			while(true) {
    
				//向服务器写出一行数据,并且读取服务器响应回来的数据
				PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
				BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				//3.通过流对象进行发送和读取的操作
				System.out.println("请输入您想给服务器发送的数据:");
				String input = new Scanner(System.in).nextLine();
				out.println(input);//向服务端发送指定数据
				out.flush();//把数据刷出去
				String line = in.readLine();//读取回声数据
				System.out.println("服务器端响应的数据是:"+line);
			}
		} catch (Exception e) {
    
			e.printStackTrace();
		}
	}
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43884234/article/details/115075016

智能推荐

Ajax请求的五个步骤_js ajax请求的五个步骤-程序员宅基地

文章浏览阅读3.6w次,点赞22次,收藏150次。一、原生JS中的Ajax:1、使用ajax发送数据的步骤第一步:创建异步对象var xhr = new XMLHttpRequest();第二步:设置 请求行 open(请求方式,请求url):// get请求如果有参数就需要在url后面拼接参数,// post如果有参数,就在请求体中传递 xhr.open("get","validate.php?username="+name)xhr.open("post","validate.php");第三步:设置请求(GET方式忽略此步骤)头:s_js ajax请求的五个步骤

云数据库POLARDB优势解读系列文章之②——高性价比-程序员宅基地

文章浏览阅读180次。现在做任何事情都要看投入产出比,对应到数据库上其实就是性价比。POLARDB作为一款阿里自研数据库,经常被问的问题是:性能怎么样?能不能支撑我的业务?价格贵不贵?很显然,在早期调研阶段,对稳定性、可靠性很难有量化的指标时,性能的好快就成了一个非常关键的决策因子。POLARDB在一开始设计时就把性能作为一项关键的需求指标列入产品需求说明书,从架构设计到新硬件选型,再到代码实现,从驱动到分布式块存...

ibatis与springmvc出现Check the result mapping for the 'xxx' property的错误_check the result mapping for the 'rownum_' propert-程序员宅基地

文章浏览阅读7.7k次。有与项目需要,将数据库中的一个表增加了一个字段。_check the result mapping for the 'rownum_' property.

对文件指定行进行编辑和保存 linux,linux 文本编辑命令grep sed awk(转)-程序员宅基地

文章浏览阅读641次。[:digit:] 数字字符[:graph:] 非空字符(非空格、控制字符)[:lower:] 小写字符[:cntrl:] 控制字符[:print:] 非空字符(包括空格)[:punct:] 标点符号[:space:] 所有空白字符(新行,空格,制表符)[:upper:] 大写字符[:xdigit:] 十六进制数字(0-9,a-f,A-F)4. Grep命令选项-? 同时显示匹配行上下的?行,如:...

协同过滤算法之基于物品的推荐算法-程序员宅基地

文章浏览阅读829次。目前有关个性化推荐算法主要分为三大类:1.基于协同过滤的推荐;2.基于内容过滤的推荐和3.社会化推荐。本文主要讨论基于协同过滤的推荐,而该算法也可以划分为两类:1.基于用户的协同过滤算法(UserCF)该算法利用用户之间的相似性来推荐用户感兴趣的信息,个人通过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信...

elasticesearch安装head插件_elastic head-程序员宅基地

文章浏览阅读901次。1.下载elasticsearch的head压缩包:下载地址:https://github.com/mobz/elasticsearch-head;点击clone or download按钮,点击download zip进行下载。下载完毕后解压到任意路径上,别放在elasticsearch安装路径上。2.下载node.js:下载地址:https://nodejs.org/en/do..._elastic head

随便推点

文章:叶绿体 rRNA 甲基转移酶 CMAL 在核糖体形成和植物发育中的关键作用_dii-venus-程序员宅基地

文章浏览阅读1.5k次。INTRODUCTION核糖体 RNA(rRNA)中核苷酸的甲基化是在所有活生物体中普遍存在的特征。目前对 RNA 甲基化酶的结构及其如何对 RNA 进行甲基化有了一定的了解,但是对质体中 RNA 甲基化过程以及甲基化对生理过程的影响仍然知之甚少。迄今为止,在植物叶绿体内通过实验鉴定出了三种形式的 RNA 甲基化,但尚未有人研究出导致上述 RNA 甲基的甲基转移酶。本研究中,作者在拟南芥的叶绿体中鉴定出了一种 rRNA 甲基转移酶 CMAL(Chloroplast MraW-Like)。 CMAL 可以将_dii-venus

PCI设备的配置空间_pci-1753 配置丢失-程序员宅基地

文章浏览阅读2.4k次,点赞2次,收藏4次。在一个具体的处理器应用中,PCI设备通常将PCI配置信息存放在E2PROM中。PCI设备进行上电初始化时,将E2PROM中的信息读到PCI设备的配置空间中作为初始值。这个过程由硬件逻辑完成,绝大多数PCI设备使用这种方式初始化其配置空间。读者可能会对这种机制产生一个疑问,如果系统软件在PCI设备将E2PROM中的信息读到配置空间之前,就开始操作配置空间,会不会带来问题?因为此时PCI设备的初始_pci-1753 配置丢失

linux生成iso文件怎么打开吗,iso文件扩展名,iso文件怎么打开?-程序员宅基地

文章浏览阅读155次。.iso文件类型:Disc Image File扩展名为.iso的文件是一个磁盘文件。文件说明:Common CD or DVD disc image format based on the ISO-9660 standard; contains an exact duplicate of data from the original disc; includes the data saved o..._扩展名iso怎么打开

语音识别,标注数据_语音识别剪切标注-程序员宅基地

文章浏览阅读1.7k次。切割音频文件from pydub import AudioSegmentfrom pydub.silence import split_on_silenceimport ossound = AudioSegment.from_mp3("E:/data/AcsData/zfBX/hw202003301111246_23401.wav")loudness = sound.dBFSoutputPath = "E:/data/AcsData/zfBX/output/"chunks = split_o_语音识别剪切标注

nginx配置反向代理后,网页可以正常访问,但是页面上的js、 css、 视频文件、音乐文件无法加载到_nginx反代视频无法播放-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏2次。nginx配置反向代理后,网页可以正常访问,但是页面上的js、 css、 视频文件、音乐文件无法加载到问题为路径问题、将相对路径改为绝对路径即可,一段代码即可解决 location / { root /home/rock/www/website/WE/html; index home.html; } location ~* .(jpg|gif|p..._nginx反代视频无法播放

Windows Server ORA-27101: shared memory realm does not exist.-程序员宅基地

文章浏览阅读411次。风吹起了从前,看着天边似在眼前,万般流连~_ora-27101: shared memory realm does not exist

推荐文章

热门文章

相关标签