网络编程Socket
Posted 猪八戒1.0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程Socket相关的知识,希望对你有一定的参考价值。
一.基本介绍
网络三要素:ip,端口,协议
TCP保证接收,UDP不管是否接收到,是不可靠协议。
二.UDP协议的Socket
由于UDP是不可靠协议,不管你是否能够接收到,所以当只写了客户端,没写服务端时,运行并不会报错。而实际一般都是先写服务端再写客户端
客户端
package test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class Send
public static void main(String[] args)
/*
* DatagramSocket
* 1.创建对象
* 2.把想发送的数据打包(并且不超过64K)
* 3.发送
* */
DatagramSocket ds=null;
try
ds=new DatagramSocket();
//ip和端口号都是指服务器的ip和端口号
byte[] buf="发送了UDP协议的数据".getBytes(StandardCharsets.UTF_8);
InetAddress adress=InetAddress.getByName("此处填自己电脑ip地址");
DatagramPacket dp=new DatagramPacket(buf,buf.length,adress,10086);
ds.send(dp);
catch (Exception e)
throw new RuntimeException(e);
finally
if(ds!=null)
ds.close();
服务端
package test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Receive
public static void main(String[] args)
/*
* 1.创建接收方对象 new DatagramSocket(10086);需要指定接收的端口
* 2.创建一个数据包
* 3.从数据包DatagramPacket里面接收数据
* */
DatagramSocket ds=null;
try
//指定哪个端口接收
ds=new DatagramSocket(10086);
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);//阻塞方法 也就是等着客服端发送
System.out.println(dp.getPort());//得端口号
System.out.println(dp.getAddress());//得ip地址
//输出客户端发送的信息
byte[] b=dp.getData();
//如果是b.length会出现很多空余
//System.out.println(new String(b,0,b.length));
System.out.println(new String(b,0,dp.getLength()));
catch (Exception e)
throw new RuntimeException(e);
运行结果
看服务端最后 b.length过多出现如下效果
改为 dp.getLength()
实际需要保证服务端一直运行,所以使用while(true)
服务端
package test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Receive
public static void main(String[] args)
/*
* 1.创建接收方对象 new DatagramSocket(10086);需要指定接收的端口
* 2.创建一个数据包
* 3.从数据包DatagramPacket里面接收数据
* */
DatagramSocket ds=null;
try
//指定哪个端口接收
ds=new DatagramSocket(10086);
while (true)
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);//阻塞方法 也就是等着客服端发送 走完这一步之后就已经获取到数据包了
//输出客户端发送的信息
byte[] b=dp.getData();
System.out.println(new String(b,0,dp.getLength()));
catch (Exception e)
throw new RuntimeException(e);
客户端
package test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class Send
public static void main(String[] args)
/*
* DatagramSocket
* 1.创建对象
* 2.把想发送的数据打包(并且不超过64K)
* 3.发送
* */
DatagramSocket ds=null;
BufferedReader br;
try
ds=new DatagramSocket();
br=new BufferedReader(new InputStreamReader(System.in));
String line="";
while ((line=br.readLine())!=null)
if(line.equals("886"))
break;
InetAddress adress=InetAddress.getByName("此处写自己电脑ip地址");
DatagramPacket dp=new DatagramPacket(line.getBytes(StandardCharsets.UTF_8)
, line.length(),adress,10086);
ds.send(dp);
catch (Exception e)
throw new RuntimeException(e);
finally
if(ds!=null)
ds.close();
程序没有问题,运行可能出现乱码情况,这是代码编辑器的问题
三.TCP协议
可靠协议,必须建立连接通道,在连接通道内进行数据传输,通过三次握手建立连接
socket双向通信
服务端
package test;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Service
public static void main(String[] args)
ServerSocket server=null;
try
server=new ServerSocket(10086);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
byte[] b=new byte[1024];
int len=0;
while ((len=is.read(b))!=-1)
System.out.println(new String(b,0,len));
catch (IOException e)
throw new RuntimeException(e);
客户端
package test;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Client
public static void main(String[] args)
/*
* 1.创建一个客户端的socket对象
* 2.建立连接(很简单,但是不好理解)
* 3.通过io流在管道里面传输数据
* 4.关闭socket
*
* 当我们new对象的时候就建立连接了
* */
Socket client=null;
try
client=new Socket("192.168.65.216",10086) ;
//得到输出流
OutputStream os=client.getOutputStream();
os.write("tcp".getBytes(StandardCharsets.UTF_8));
catch (Exception e)
throw new RuntimeException(e);
finally
try
if(client!=null)
client.close();
catch (IOException e)
throw new RuntimeException(e);
上传图片
使用flush刷新下比较好,不用可能图片少一点
package test1;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
public static void main(String[] args)
ServerSocket server=null;
try
server=new ServerSocket(10000);
Socket client = server.accept();
//client.getInputStream()得到客户端数据
BufferedInputStream bis=new BufferedInputStream(client.getInputStream());
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("new.jpg")) ;
byte[] b=new byte[1024];
int len=0;
while ((len=bis.read(b))!=-1)
bos.write(b,0,len);
bos.flush();
bos.close();
client.close();
server.close();
catch (Exception e)
throw new RuntimeException(e);
package test1;
import java.io.*;
import java.net.Socket;
public class Client
public static void main(String[] args)
Socket client = null;
try
client = new Socket("电脑ip", 10000);
BufferedOutputStream bos =new BufferedOutputStream(client.getOutputStream()) ;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\\\Users\\\\27955\\\\Desktop\\\\1.jpg"));
byte[] b = new byte[1024];
int len = 0;
while ((len = bis.read(b)) != -1)
bos.write(b, 0, len);
bos.flush();
bis.close();
client.close();
catch (IOException e)
throw new RuntimeException(e);
服务器向客户端发送信息
package test1;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class Client1
public static void main(String[] args) throws IOException
Socket client = new Socket("电脑ip",10001);
InputStream is = client.getInputStream();
byte[] b=new byte[1024];
int len=0;
while ((len=is.read(b))!=-1)
System.out.println(new String(b,0,len));
package test1;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server1
public static void main(String[] args) throws IOException
ServerSocket server= new ServerSocket(10001);
Socket client = server.accept();
OutputStream os = client.getOutputStream();
os.write("hahaha".getBytes(StandardCharsets.UTF_8));
client.close();
四.综合练习
编写服务端用于接收上传的图片,连接用的端口号为 10203,接收到的图片存储于 /home/project/pic 目录中,并将其命名为 mn.jpg,接收完成后向客户端传输一个 “接收完成” 。
编写客户端用于上传图片。接收到服务端“接收完成”的信息后,向控制台输出 “上传完成” 。
package service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class UploadService
public static void main(String[] args)
ServerSocket server=null;
try
server=new ServerSocket(10203);
Socket client = server.accept();
//client.getInputStream()得到客户端数据
BufferedInputStream bis=new BufferedInputStream(client.getInputStream());
OutputStream os = client.getOutputStream();
os.write("接收完成".getBytes(StandardCharsets.UTF_8));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("/home/project/pic/mn.jpg")) ;
byte[] b=new byte[1024];
int len=0;
while ((len=bis.read(b))!=-1)
bos.write(b,0,len);
bos.flush();
bos.close();
client.close();
server.close();
catch (Exception e)
throw new RuntimeException(e);
package client;
import java.io.*;
import java.net.Socket;
public class UploadClient
public static void main(String[] args)
Socket client = null;
try
client = new Socket("localhost", 10203);
BufferedOutputStream bos =new BufferedOutputStream(client.getOutputStream()) ;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/home/project/pic/timg.jpg"));
byte[] b = new byte[1024];
int len = 0;
while ((len = bis.read(b)) != -1)
bos.write(b, 0, len);
bos.flush();
InputStream is = client.getInputStream();
byte[] b2=new byte[1024];
int len2=0;
while ((len2=is.read(b2))!=-1)
if((new String(b2,0,len2)).equals("接收完成"))
System.out.println("上传完成");
bis.close();
client.close();
catch (IOException e)
throw new RuntimeException(e);
五.使用底层技术实现爬虫操作
爬虫可以将网络上的资源作为己用,但是那些资源的拥有者是否允许开发者爬取他们的数据呢? 🙄
因此在使用爬虫时,稍有不慎,就可能面临法律纠纷,大家在使用爬虫时务必要注意法律问题。
以下列举的一些禁止爬取的场景,但由于非法律专业人员,以下列举场景仅供大家参考,爬虫的禁止场景并不限于此。
在实际工作中,如果有涉及爬虫开发的地方,建议大家务必咨询一下公司的法务人员或者相关法律人士。
不要大规模的爬取网络数据,或对对方的服务器造成较大影响。
不要将爬虫用于灰色产业、敏感行业,或使用爬虫非法获利。
不要使用爬虫获取网站或用户的隐私数据。
不要违背 robots 协议或经营者意志。
不要使用爬虫进行任何法律、法规或道德禁止的行为。
从技术体系而言,爬虫可以分为三个部分:获取海量数据、解析数据和存储数据。
接下来,我们模拟爬取蓝桥云课首页的数据。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
/**
* 爬虫获取海量数据
*/
public class TestCrawler
//获取蓝桥云课首页的html源码
public static String getResource()
BufferedReader reader = null;
// 创建字符串缓冲区,存放爬取的数据
StringBuffer html = new StringBuffer();
try
// 创建 URL 对象
URL url = new URL("https://www.lanqiao.cn/");
// 通过 URL 对象获取 URLConnection 对象
URLConnection urlConnection = url.openConnection();
// 建立连接
urlConnection.connect();
// 通过 IO 流提取数据信息
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null)
html.append(line);
catch (Exception e)
e.printStackTrace();
finally
// 流资源释放
try
if (reader != null)
reader.close();
catch (IOException e)
e.printStackTrace();
return html.toString();
public static void main(String[] args)
String html = getResource();
System.out.println("蓝桥云课首页的源码如下所示:\\n"+html);
作为简单的模拟爬虫,我们实现从源码中解析出网站标题,即上述 <meta> 标签中的 content 值。
🤔 那么如何解析呢?
我们知道,源码其实就是字符串,因此完全可以用字符串解析的相关方法进行解析。
但纯字符串解析有些繁琐,本次会采用 “正则表达式+字符串解析” 结合的方式来获取 content 值。
正则表达式描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串,可替换匹配的子串,或者提取匹配的子串。
👉 这里我们回顾一下之前学过的正则表达式的常用方法,如下所示:
Pattern.compile(String regex):根据参数 regex 创建一个正则表达式实例;
Matcher matcher(CharSequence input):对整个输入字符串 input 进行匹配。
假设现在要在 A 字符串中,查找是否含有 B 内容,就可以通过以下形式进行匹配查询:
Pattern pattern = Pattern.compile(A);
Matcher matcher = pattern.matcher(B);
之后再结合 matcher.find() 方法进行正则匹配,如果 matcher.find() 的返回值是 true,就说明 A 中存在符合条件的 B,否则说明不存在。
修改已存在的 TestCrawler.java 源文件,添加一个 parseResource() 方法,用来完成从蓝桥云课首页的源码中解析出 <meta> 标签中的 content 属性值,源代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 爬虫获取海量数据
*/
public class TestCrawler
//获取蓝桥云课首页的html源码
public static String getResource()
BufferedReader reader = null;
// 创建字符串缓冲区,存放爬取的数据
StringBuffer html = new StringBuffer();
try
// 创建 URL 对象
URL url = new URL("https://www.lanqiao.cn/");
// 通过 URL 对象获取 URLConnection 对象
URLConnection urlConnection = url.openConnection();
// 建立连接
urlConnection.connect();
// 通过 IO 流提取数据信息
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null)
html.append(line);
catch (Exception e)
e.printStackTrace();
finally
// 流资源释放
try
if (reader != null)
reader.close();
catch (IOException e)
e.printStackTrace();
return html.toString();
// 从蓝桥云课首页的源码中解析特定的数据
public static String parseResource(String html)
/*
(.+?) :表示匹配一次符合条件的值,即从蓝桥网首页的源码中,寻找以下内容:
<meta data-n-head="ssr" data-hid="description" name="description" content=
*/
Pattern pattern = Pattern.compile("meta data-n-head=\\"ssr\\" data-hid=\\"description\\" name=\\"description\\" content=\\"(.+?)\\"");
//从蓝桥云课首页的源码中,提取符合pattern约束的字符串
Matcher matcher = pattern.matcher(html);
String result = null;
//判断是否存在 符合约束的字符串
if (matcher.find())
//提取出全部符合条件的值,即提取出<meta>标签中的content属性值
result = matcher.group(0);
result = result.substring(result.indexOf("content=") + "content=".length());
return result;
public static void main(String[] args)
String html = getResource();
// System.out.println("蓝桥云课首页的源码如下所示:\\n"+html);
String result = parseResource(html);
System.out.println(result == null ? "爬取失败" : "description 的 content 值是:" + result);
总结
本实验主要讲解的是爬虫获取海量数据和解析数据。
通过 URLConnection 类完成数据爬取操作。
数据的获取也是离不开 IO 流的,因此流是无处不在的。
将之前所学的字符串缓冲区、IO 流和网络编程结合进行操作,同时也可以巩固所学的知识。
通过 Java 自带的正则表达式类完成数据解析操作。
通过 Pattern 和 Matcher 类进行正则匹配操作。
字符串中的 substring()、indexOf() 和 length() 常用方法进行处理。
模拟了爬取网页的数据信息,这虽然在搜集海量数据的时候非常有用,但是不能随意使用,因为随意爬取有些网站的数据是可以构成违法行为的,一点要谨慎使用
以上是关于网络编程Socket的主要内容,如果未能解决你的问题,请参考以下文章