socket编程

分为服务端和客户端,服务端采用NIO的模式,由于传统的模式可能存在消息堵塞的情况,可能需要用到多线程技术,实现起来难度较大,且耗cpu性能,没有特别要求的,或者对多线程技术不是很了解的,不建议使用,这里NIO可以很好解决这种问题JDK1.4以上就支持NIO了,我这里的程序都是在JDK1.8的环境下测试过,请大家参考,另外如果用到和前端页面的消息交互的话可以用websocket,例如网页聊天,请看我的另一篇博客https://blog.csdn.net/u011267841/article/details/103611624

1.服务端

package com.example.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@PropertySource("classpath:socket.properties")
public class NIOServer {

    @Value("${port}")
    private Integer port;
    
	  public void startNIO() throws IOException{

			//Integer port=8080;
			
		    // 创建网络服务端ServerSocketChannel
		    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		    // 设置为非阻塞模式
		    serverSocketChannel.configureBlocking(false);

		    // 构建一个Selector选择器,并且将channel注册上去
		    Selector selector = Selector.open();
		    // 将serverSocketChannel注册到selector
		    SelectionKey selectionKey = serverSocketChannel.register(selector, 0, serverSocketChannel);
		    // 对serverSocketChannel上面的accept事件感兴趣(serverSocketChannel只能支持accept操作)
		    selectionKey.interestOps(SelectionKey.OP_ACCEPT);

		    // 绑定端口
		    serverSocketChannel.socket().bind(new InetSocketAddress(port));
		    log.info("启动成功,占用端口号:"+port);

		    while (true) {
		      // 不再轮询通道,改用下面轮询事件的方式.select方法有阻塞效果,直到有事件通知才会有返回
		      selector.select();
		      // 获取事件
		      Set<SelectionKey> keys = selector.selectedKeys();
		      // 遍历查询结果
		      Iterator<SelectionKey> iterator = keys.iterator();
		      while (iterator.hasNext()) {
		        // 被封装的查询结果
		        SelectionKey key = iterator.next();
		        iterator.remove();
		        // 关注 Read 和 Accept两个事件
		        if (key.isAcceptable()) {
		          ServerSocketChannel server = (ServerSocketChannel) key.attachment();
		          // 将拿到的客户端连接通道,注册到selector上面
		          SocketChannel clientSocketChannel = server.accept();
		          clientSocketChannel.configureBlocking(false);
		          clientSocketChannel.register(selector, SelectionKey.OP_READ, clientSocketChannel);
		          log.info("收到新连接 : " + clientSocketChannel.getRemoteAddress());
		        }
		        if (key.isReadable()) {
		          SocketChannel socketChannel = (SocketChannel) key.attachment();
		          try {
		            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		            while (socketChannel.isOpen() && socketChannel.read(byteBuffer) != -1) {
		              // 长连接情况下,需要手动判断数据有没有读取结束 (此处做一个简单的判断: 超过0字节就认为请求结束了)
		              if (byteBuffer.position() > 0) break;
		            }

		            if (byteBuffer.position() == 0) continue;
		            byteBuffer.flip();
		            byte[] content = new byte[byteBuffer.limit()];
		            byteBuffer.get(content);
		            log.info(new String(content));
		            log.info("收到数据,来自:" + socketChannel.getRemoteAddress());

		            // 响应结果 200
		            String response = "HTTP/1.1 200 OK\r\n" + "Content-Length: 11\r\n\r\n" + "Hello World";
		            ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
		            while (buffer.hasRemaining()) {
		              socketChannel.write(buffer);
		            }

		          } catch (Exception e) {
		            e.printStackTrace();
		            key.cancel(); // 取消事件订阅
		          }
		        }

		        selector.selectNow();
		      }
		    }
		  
	  }
	}

注意port就是你的配置文件的端口号,在resources目录下,我这里配置的是8080

2.客户端程序采用普通的socket的写法即可

package com.example.nio;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;
import java.util.UUID;

@Slf4j
public class Client {

    public static void main(String[] args) throws IOException {
        String host = "localhost";
        int port = 8080;

        //与服务端建立连接
        Socket socket = new Socket(host, port);
        socket.setOOBInline(true);
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String sendData = scanner.nextLine();
            log.info("输入内容为:"+sendData);
            socket.getOutputStream().write(sendData.getBytes("UTF-8"));
            if("end".equals(sendData)) {
                //结束会话
                break;
            }
        }

    }
}

3.SpringBoot启动程序


@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) throws BeansException, IOException {
        //SpringApplication.run(DemoApplication.class, args);
    	//起socket服务
        ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
        applicationContext.getBean(NIOServer.class).startNIO();//在spring容器启动后,取到已经初始化的NIOServer,启动Socket服务
        
        

        

    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值