Socket
服务端: 监听
客户端: 连接
Socket本身是一样的,客户端的是请求,服务端是响应,他们之间可以传递流。
一个套接字: 客户端请求
一个套接字: 服务端处理
一个连接就是一对套接字
联系:
socket相当于流缓冲区,都通过各自socket来获取流中的数据。2端socket通过一条固定"电话线"进行通讯,即Client端选择跟哪台Server,哪个端口建立连接;作为Server端只监听相应的端口。在这里,Client处于主动。
建立连接后,两端都可以使用流通过socket相互的发送信息和接受信息。两端的socket都会不断刷新socket里的内容。
区别:
在通讯完毕后,Server端的线程会关闭socket连接
区别在于,通讯前
服务器端套接在 在某一端口处监听客户端的连接,等客户端连接
客户端连接服务器端的 ip 和端口,
等双方连接起来的时候 就可以互相通讯,双方没有区别了。
两个Socket形成一个相互连接的Socket接口,在Client端和Server建立一个可以通讯的通道
InputStream in = new InputStream(s.getInputStream());
OutputStream out = new OutputStream(s.getOutputStream());
就可以在两端建立一个用于通讯输入输出流
客户端会创建的套接字Socket和服务器端的accept()方法返回的套接字Socket进行通信,而ServerSocket创建的套接字只是用于监听客户端的连接请求,而不进行通信
1)Java中的Socket用法Java中的Socket分为普通的Socket和NioSocket。
2)普通Socket用法创建ServerSocket。ServerSocket的构造方法有5个,其中最方便的是ServerSocket(int port),只需要一个port就可以了。 Java中的网络通信时通过Socket实现的,Socket分为ServerSocket和Socket两大类,ServerSocket用于服务器端,可以通过accept方法监听请求,监听请求后返回Socket,Socket用于完成具体数据传输,客户端也可以使用Socket发起请求并传输数据。ServerSocket的使用可以分为三步:调用创建出来的ServerSocket的accept方法进行监听。accept方法是阻塞方法,也就是说调用accept方法后程序会停下来等待连接请求,在接受请求之前程序将不会继续执行,当接收到请求后accept方法返回一个Socket。使用accept方法返回的Socket与客户端进行通信
如下代码,我们在服务器端创建ServerSocket,并调用accept方法监听Client的请求,收到请求后返回一个Socket
public class Server {
public static void main(String[] args) { // TODO Auto-generated method stub
try {
//创建一个ServerSocket监听8080端口 ServerSocket server = new ServerSocket(8080); //等待请求 Socket socket = server.accept(); //接受请求后使用Socket进行通信,创建BufferedReader用于读取数据 BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = is.readLine(); System.out.println("received frome client:" + line); //创建PrintWriter,用于发送数据 PrintWriter pw = new PrintWriter(socket.getOutputStream()); pw.println("this data is from server"); pw.flush(); //关闭资源 pw.close(); is.close(); socket.close(); server.close(); }
catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } }
然后我们再看看客户端的Socket代码,Socket的使用也是一样,首先创建一个Socket,Socket的构造方法非常多,这里用的是Socket(String host, int port),把目标主机的地址和端口号传入即可(本实验代码中服务器和Client代码没有在同一台机器上,服务器的IP地址:192.168.6.42,所以如果读者在实验过程中ServerSocket和Client在同一主机下,那么Client中的IP地址需要更改为:127.0.0.1,Socket创建的过程就会跟服务器端建立连接,创建完Socket后,再创建Writer和Reader来传输数据,数据传输完成后释放资源关闭连接。
public class Client {
public static void main(String[] args) { // TODO Auto-generated method stub String msg = "Client data";
try {
//创建一个Socket,跟服务器的8080端口链接 Socket socket = new Socket("192.168.6.42",8080); //使用PrintWriter和BufferedReader进行读写数据 PrintWriter pw = new PrintWriter(socket.getOutputStream()); BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream())); //发送数据 pw.println(msg); pw.flush(); //接收数据 String line = is.readLine(); System.out.println("received from server" + line); //关闭资源 pw.close(); is.close(); socket.close(); }
catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); }
catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } }
最后先启动Server然后启动Client就可以完成一次Client和Server的通信。
3)NioSocket的用法 在了解NioSocket之前我们先了解Buffer、Channel、Selector。为了方便理解,我们来看个例子,要过圣诞节了,需要给同学们发贺卡和苹果,班长这时候又是最辛苦的,每次拿一个苹果和一张贺卡发给一个同学,发送完成后回来再取一张贺卡和一个苹果发给另一个同学,直到全班同学都拿到贺卡和苹果为止,这就是普通Socket处理方式,来一个请求,ServerSocket就进行处理,处理完成后继续接受请求,这种方式效率很低啊!还是圣诞节的例子,班长发现班委不止他一个,就通知了生活委员(女)和组织委员(男)来帮助他发贺卡和苹果,女生的贺卡是粉色的,男生的贺卡是蓝色的,生活委员负责从全班的贺卡中挑选女生的贺卡,而组织委员则负责男生的贺卡,然后生活委员和组织委员分别以宿舍为单位通知宿舍长来领取宿舍同学的贺卡和苹果,班长将圣诞节发苹果和贺卡的工作布置给两个班委后,就可以继续干其他工作了。这就是NioSocket,Buffer就是所有传递的货物,也就是例子中的苹果和贺卡,而Channel就是传递货物的通道,也就是例子中的宿舍长,负责将礼物搬回自己宿舍,而生活委员和组织委员充当了Selector的职责,负责礼物的分拣。 从JDK1.4开始,Java增加了新的IO模式-nio(new IO),nio在底层采用了新的处理方式,极大提高了IO的效率。我们使用的Socket也是IO的一种,nio提供了相应的工具:ServerSocketChannel和SocketChannel,他们分别对应原来的ServerSocket和Socket。
ServerSocketChannel可以使用自己的静态工厂方法open创建,每个ServerSocketChannel对应一个ServerSocket(通过调用其socket()获取),如果直接使用获取的ServerSocket来监听请求,那么还是普通ServerSocket,而通过将获取的ServerSocket绑定端口号来实现NioSocket。ServerSocketChannel可以通过configureBlocking方法来设置是否采用阻塞模式,如果设置为非阻塞模式,就可以调用register方法注册Selector来使用了。
Selector可以通过其静态工厂方法open创建,创建后通过Channel的register方法注册到ServerSocketChannel或者SocketChannel上,注册完成后Selector就可以通过select方法来等待请求,select方法有一个long类型参数,代表最长等待时间,如果在这段时间内收到相应操作的请求则返回可以处理的请求的数量,否则在超时后返回0,如果传入的参数为0或者无参数的重载方法,select方法会采用阻塞模式知道有相应操作请求的出现。当接收到请求后Selector调用selectdKeys方法返回SelectionKey集合。
SelectionKey保存了处理当前请求的Channel和Selector,并且提供了不同的操作类型。Channel在注册Selector时可以通过register的第二个参数选择特定的操作(请求操作、连接操作、读操作、写操作),只有在register中注册了相应的操作Selector才会关心相应类型操作的请求。
介绍了这么多估计大家也烦了,我们就来看看服务器端NioSocket的处理过程吧:
1.创建ServerSocketChannel并设置相应的端口号、是否为阻塞模式
2.创建Selector并注册到ServerSocketChannel上
3.调用Selector的selector方法等待请求
4.Selector接收到请求后使用selectdKeys返回SelectionKey集合
5.使用SelectionKey获取到channel、selector和操作类型并进行具体操作。
public class NIOServer { public static void main(String[] args) { // TODO Auto-generated method stub try { //创建ServerSocketChannel,监听8080端口 ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8080)); //设置为非阻塞模式 ssc.configureBlocking(false); //为ssc注册选择器 Selector selector = Selector.open(); ssc.register(selector, SelectionKey.OP_ACCEPT); //创建处理器 Handler handler = new Handler(1024); while(true){ //等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传入参数则一直阻塞 if(selector.select(3000) == 0){ System.out.println("等待请求超时----"); continue; } System.out.println("处理请求----"); //获取处理的SelectionKey Iterator keyIter = selector.selectedKeys().iterator(); while(keyIter.hasNext()){ SelectionKey key = keyIter.next(); try{ //接收到连接请求时 if(key.isAcceptable()){ handler.handleAccept(key); } //读数据 if(key.isReadable()){ handler.handleRead(key); } }catch(IOException ex){ keyIter.remove(); continue; } //处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key keyIter.remove(); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static class Handler{ private int bufferSize = 1024; private String localCharset = "UTF-8";
客户端代码通普通Socket一样,Socket socket = new Socket("192.168.6.42",8080);表示与服务器端建立连接,从而执行服务器端的handleAccept()方法,给ServerSocketChannel注册selector以及添加SelectionKey.OP_READ参数,表示selector关心读方法。然后通过PrintWrite在客户端将内容发送给服务器端,服务器端执行handleRead方法对接收到的内容进行处理,并将结果返回给客户端,客户端通过BufferedReader接受数据,最后关闭连接。如果意犹未尽的话,请转看Java NIO。
服务端Server监听端口获取数据案例代码
@Slf4j
@Component
public class CommandCarGpsSocket extends Thread implements InitializingBean{
@Autowired
GpsHistoryService gpsHistoryService;
private static final int PORT = 9999;
@Override
public void afterPropertiesSet(){
start();
}
private void threadGetData(){
// TODO Auto-generated method stub
//本级平台资源编码
//获取当前平台的系统编码
String systemCode = (String) CommonCatche.getInstance().get(IConfKeyConstant.system_code);
if(StringUtils.isNotBlank(systemCode)){
String substring = systemCode.substring(1, 13);
if("650000000000".equals(substring)){
try {
log.info("socket建立链接");
//创建ServerSocketChannel,监听8080端口
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(PORT));
//设置为非阻塞模式
ssc.configureBlocking(false);
//为ssc注册选择器
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
//创建处理器
Handler handler = new Handler(1024);
while(true){
//等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传入参数则一直阻塞
if(selector.select(3000) == 0){
log.info("等待请求超时----");
continue;
}
log.info("处理请求----");
//获取处理的SelectionKey
Iterator keyIter = selector.selectedKeys().iterator();
while(keyIter.hasNext()){
SelectionKey key = keyIter.next();
try{
//接收到连接请求时
if(key.isAcceptable()){
handler.handleAccept(key);
20004000元爆款大容量冰箱购买指南平时常看别人花大几千字教人如何挑冰箱,然而挑来挑去不离一句话越贵越牛X。其实,针对普通家庭,记住一句挑选口诀就好要想冰箱选得好,容量选大不选小,变频风冷多循环,显示屏可没必要话不多
露营风悄然出圈,适合露营的MPV又有哪些?今年以来,露营成为了一种大热的休闲方式,各式各样的露营装备五花八门的露营地点,不断刷屏人们的朋友圈。关于露营,很重要的一个因素就是要有一台合适的车,而MPV作为大空间实用性的代表,
央媒看湖南湖南近郊游尽享烟火气息国庆假期到来,旅游市场迎来一波热潮。记者走访发现,不少长沙市民选择留在本地过节,以露营野餐踏景赏花田园农趣等为主题的近郊游备受青睐。10月1日一早,位于长沙县金井镇的三珍虎园迎来了
三原一天游,看什么十月二日,虽无雨,但天气依然是阴沉沉的,仿佛随时都可能下起雨来,高速上还有不小雾气,所以车开的不快,不光是我们的不快,大家的车都不快,十一点的天光了,就像是傍晚七八点,朦朦胧胧地,
分享我这个超级奶爸的育儿至三岁心得简单介绍一下,我家宝宝刚满三岁零一个月,女宝,身高105,体重35,体检全部上等!识字100以上,会完成30个拼碎片完整拼图会从进口走到出口的复杂迷宫,串线迷宫认识1到100的数字
欧冠分析利物浦在英超遭遇连平,阿诺德沦为笑柄,标王成水货?本场欧冠小组赛的比赛,英超豪门利物浦将会在主场对战苏超老字号格拉斯哥流浪者的比赛,这场强弱十分悬殊的比赛将会在北京时间10月5日凌晨3时开打。利物浦近况红军在周末的联赛中没有如愿地
昆山皮尔洛!38岁汪嵩领跑中甲助攻榜,一起来看看他的大师级传球职业生涯曾经效力于浙江绿城广州富力和江苏苏宁的中场大师汪嵩已经渐渐淡出了中超球迷的视野,已经年满38岁的他仍然在中甲的赛场发光发热,目前是石家庄功夫队不可或缺的大将,本赛季他已经累
英超第九轮综述英超第九轮比赛全部结束,本轮两场德比战都非常精彩,德比的结果也比较合理,但是因为有部分球到少赛一场甚至两场所以目前的积分情况并不是最完整的,而且值得一提的是就是在这样的情况下前六名
意甲积分榜大黑马21疯狂压哨绝杀,逆转升第3!AC米兰跌出前410月4日凌晨2点45分,意甲联赛焦点大战,第8轮重磅对决上演。维罗纳主场对阵乌迪内斯,备受关注。此役第23分钟,维罗纳后卫在禁区内获得打门机会,左脚抽射入网,比分来到10!第70
室内取暖设备哪种效果好冬季取暖器最好品牌室内取暖设备哪种效果好冬季取暖器最好品牌这个世界上,应该没有人是不怕冷的吧!虽说大家都怕冷,但在怕冷的程度上,南北是有差异的。如果光看温度显示的数字,应该北方的冬季气温要比南方低得
CBA三消息新疆选秀挖到宝藏,齐麟热身砍288,朱旭航两双5三分大家好呀,我是北柠,各位小伙伴们要养成先赞后看的习惯哦!新疆队上个赛季常规赛排在联盟中的第十四位,这个成绩说实话是不太理想的,他们没能打进季后赛,而且常规赛第十四位也很难获得选秀大