TCP客户服务端
- 创建TCP服务端
1.创建一个ServerSocket对象。
2.调用accept()方法接收客户端请求。
3.从Socket中获取I/O流。
4.对I/O流进行读写操作,完成与客户端的交互。
5.关闭I/O流和Socket
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class Server {
- public static void main(String[] args) throws Exception {
- // 监听指定的端口
- int port = 55533;
- ServerSocket server = new ServerSocket(port);
- // server将一直等待连接的到来
- System.out.println("server将一直等待连接的到来");
- Socket socket = server.accept();
- // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
- InputStream inputStream = socket.getInputStream();
- byte[] bytes = new byte[1024];
- int len;
- inputStream.read(bytes);
- // StringBuilder s = new StringBuilder();
- String s=null;
- //只有当客户端关闭它的输出流的时候,服务端才能取得结尾的-1
- while ((len = inputStream.read(bytes)) != -1) {
- // 注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
- // s.append(new String(bytes, 0, len, "UTF-8"));
- s= new String(bytes, 0, len,"utf-8");
- }
- System.out.println("server : I get your message : " + s);
- OutputStream outputStream = socket.getOutputStream();
- outputStream.write("this is server ".getBytes("UTF-8"));
- inputStream.close();
- outputStream.close();
- socket.close();
- server.close();
- }
- }
创建TCP客户端
1.创建一个Socket对象。
2.从Socket中获取I/O流。
3.对I/O流进行读写操作,完成与服务端的交互。
4.关闭I/O流和Socket
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.Socket;
- public class ClientTest {
- public static void main(String args[]) throws Exception {
- // 要连接的服务端IP地址和端口
- String host = "127.0.0.1";
- int port = 55533;
- // 与服务端建立连接
- Socket socket = new Socket(host, port);
- // 建立连接后获得输出流
- OutputStream outputStream = socket.getOutputStream();
- String message = "client: hello this is client";
- socket.getOutputStream().write(message.getBytes("UTF-8"));
- //通过shutdownOutput告诉服务器已经发送完数据,后续只能接受数据
- socket.shutdownOutput();
- InputStream inputStream = socket.getInputStream();
- byte[] bytes = new byte[1024];
- int len;
- StringBuilder sb = new StringBuilder();
- while ((len = inputStream.read(bytes)) != -1) {
- //注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
- sb.append(new String(bytes, 0, len,"UTF-8"));
- }
- System.out.println("client : I get your message " + sb);
- inputStream.close();
- outputStream.close();
- socket.close();
- }
- }
在传输过程中,客户端需要给服务端发送消息告知自己发送完成,否则服务端会一直等待,直到超时。
1、 此时需要调用方法告诉服务端,自己发送完成。
- socket.shutdownOutput(); 而不是 outputStream.close();
如果关闭输出流那模相应的Socket也关闭,相当于 socket.close();
调用shutdownOutput() ,底层会告知服务端我这边已经写完,服务端知道消息已经读取完,如果服务端有要发送的消息,会发送,如果没有直接关闭socket。
这样会使得,不能再次发送消息,如果发送需要再次建立连接。在访问频率较高时,将急需优化。
2、通过约定符号
双方约定一个短语或字符来当做发送完成的标识,比如约定 end
- Socket socket = server.accept();
- // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
- BufferedReader read=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
- String line;
- StringBuilder sb = new StringBuilder();
- while ((line = read.readLine()) != null && "end".equals(line)) {
- //注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
- sb.append(line);
- }
优点:不需要关闭流,当发送完一条消息可以再次发送
缺点:额外的结束标志占带宽,容易误判误被结束,
3、指定长度
现指定命令长度,然后读取指定长度的内容
现在首要的问题就是用几个字节指定长度呢,我们可以算一算:
- 1个字节:最大256,表示256B
- 2个字节:最大65536,表示64K
- 3个字节:最大16777216,表示16M
- 4个字节:最大4294967296,表示4G
当然我们没必要使用最大长度,而使用边长方式来表示长度:
- 第一个字节首位为0:即0XXXXXXX,表示长度就一个字节,最大128,表示128B
- 第一个字节首位为110,那么附带后面一个字节表示长度:即110XXXXX 10XXXXXX,最大2048,表示2K
- 第一个字节首位为1110,那么附带后面二个字节表示长度:即110XXXXX 10XXXXXX 10XXXXXX,最大131072,表示128K
- 依次类推
- 上面提到的这种用法适合高富帅的程序员使用,一般呢,如果用作命名发送,两个字节就够了,如果还不放心4个字节基本就能满足你的所有要求
服务端程序:
- import java.io.InputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class SocketServer {
- public static void main(String[] args) throws Exception {
- // 监听指定的端口
- int port = 55533;
- ServerSocket server = new ServerSocket(port);
- // server将一直等待连接的到来
- System.out.println("server将一直等待连接的到来");
- Socket socket = server.accept();
- // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
- InputStream inputStream = socket.getInputStream();
- byte[] bytes;
- // 因为可以复用Socket且能判断长度,所以可以一个Socket用到底
- while (true) {
- // 首先读取两个字节表示的长度
- int first = inputStream.read();
- //如果读取的值为-1 说明到了流的末尾,Socket已经被关闭了,此时将不能再去读取
- if(first==-1){
- break;
- }
- int second = inputStream.read();
- int length = (first << 8) + second;
- // 然后构造一个指定长的byte数组
- bytes = new byte[length];
- // 然后读取指定长度的消息即可
- inputStream.read(bytes);
- System.out.println("get message from client: " + new String(bytes, "UTF-8"));
- }
- inputStream.close();
- socket.close();
- server.close();
- }
- }
先读取两个字节的长度,然后读取消息,客户端程序:
- import java.io.OutputStream;
- import java.net.Socket;
- public class SocketClient {
- public static void main(String args[]) throws Exception {
- // 要连接的服务端IP地址和端口
- String host = "127.0.0.1";
- int port = 55533;
- // 与服务端建立连接
- Socket socket = new Socket(host, port);
- // 建立连接后获得输出流
- OutputStream outputStream = socket.getOutputStream();
- String message = "the first message!";
- //首先需要计算得知消息的长度
- byte[] sendBytes = message.getBytes("UTF-8");
- //然后将消息的长度优先发送出去
- outputStream.write(sendBytes.length >>8);
- outputStream.write(sendBytes.length);
- //然后将消息再次发送出去
- outputStream.write(sendBytes);
- outputStream.flush();
- //==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法
- message = "the second message!";
- sendBytes = message.getBytes("UTF-8");
- outputStream.write(sendBytes.length >>8);
- outputStream.write(sendBytes.length);
- outputStream.write(sendBytes);
- outputStream.flush();
- //==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法
- message = "the third message!";
- sendBytes = message.getBytes("UTF-8");
- outputStream.write(sendBytes.length >>8);
- outputStream.write(sendBytes.length);
- outputStream.write(sendBytes);
- outputStream.close();
- socket.close();
- }
- }
运用线程池处理并发:
服务端:
- import java.io.InputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class SocketServer {
- public static void main(String args[]) throws Exception {
- // 监听指定的端口
- int port = 55533;
- //建立服务端
- ServerSocket server = new ServerSocket(port);
- // server将一直等待连接的到来
- System.out.println("server将一直等待连接的到来");
- //如果使用多线程,那就需要线程池,防止并发过高时创建过多线程耗尽资源
- ExecutorService threadPool = Executors.newFixedThreadPool(100);
- while (true) {
- //建立会话
- Socket socket = server.accept();
- // Runnable runnable=new Runnable() {
- // @Override
- // public void run() {
- // }
- // };
- // java8 lambda 用于简化匿名类
- Runnable runnable=()->{
- try {
- // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
- InputStream inputStream = socket.getInputStream();
- byte[] bytes = new byte[1024];
- int len;
- StringBuilder sb = new StringBuilder();
- while ((len = inputStream.read(bytes)) != -1) {
- // 注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
- sb.append(new String(bytes, 0, len, "UTF-8"));
- }
- System.out.println("get message from client: " + sb);
- inputStream.close();
- socket.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- };
- threadPool.submit(runnable);
- }
- }
- }
TCP客户服务端的更多相关文章
- 利用select实现IO多路复用TCP服务端
一.相关函数 1. int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeva ...
- TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的使用 框架源码结构 补充说明 源码地址 说明 之前有好几篇博客在讲TCP/UDP通信方 ...
- Java网络编程(TCP服务端)
/* * TCP服务端: * 1.创建服务端socket服务,并监听一个端口 * 2.服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象 * 3.可以通过获 ...
- Java TCP服务端向客户端发送图片
/** * 1.创建TCP服务端,TCP客户端 * 2.服务端等待客户端连接,客户端连接后,服务端向客户端写入图片 * 3.客户端收到后进行文件保存 * @author Administrator * ...
- TCP服务端开发为例--web开发不同url请求走不同control方法
拿java的web开发为例子,相信有很多小伙伴是做j2EE开发的,htpp请求,json数据传输都是工作中经常用的,查询请求,添加请求,修改请求前端配个url,例如https://localhost/ ...
- 03-案例——多任务版TCP服务端程序开发
案例——多任务版TCP服务端程序开发 1. 需求 目前我们开发的TCP服务端程序只能服务于一个客户端,如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢?完成多任务,可以使用线程 ...
- Asp.Net项目与TCP服务端交互
private void SocketSend(string sendstr) { //将字符串转换成字节数组 Byte[] fsSize = System.Text.Encoding.Default ...
- 【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
[转]TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP ...
- python创建tcp服务端和客户端
1.tcp服务端server from socket import * from time import ctime HOST = '' PORT = 9999 BUFSIZ = 1024 ADDR ...
随机推荐
- [luoguP1415] 拆分数列(DP)
传送门 t(i,j)表示下标从i到j的数 d[i]表示以i结尾的最小的数的下标 d[i]=max(j) (1<=j<=i && t(d[j-1],j-1)<t(j,i ...
- BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 【广义后缀自动机】
题目 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴 ...
- 刷题总结——spoj1812(后缀自动机+DP)
题目: A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is t ...
- essential c++ 随笔
编写一个C++程序: vector初始化两种方法: vector<int>elem_seq(seq_size); elem_seq[0]=1 elem_seq[1]=2; 另一种方法则是利 ...
- hdu4035 Maze (树上dp求期望)
dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点1处(概率为ki) 2.找到出口,走出迷宫 ...
- request.getContextPath是为了解决相对路径的问题,可返回站点的根路径
假定你的web application 名称为news,你在浏览器中输入请求路径: http://localhost:8080/news/main/list.jsp 则执行下面向行代码后打印出如下结果 ...
- N*N数码问题
奇数码问题 时间限制: 1 Sec 内存限制: 128 MB 题目描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. ...
- 征途(bzoj 4518)
Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地.除第m天外,每一天晚上Pine都必须在休息站过夜 ...
- 实战分析Tomcat的类加载器结构(使用Eclipse MAT验证)
一.前言 在各种Tomcat相关书籍,书上都提到了其类加载器结构: 在Tomcat 7或者8中,共享类和Catalina类加载器在catalina.properties中都是没配置的,请看: 所以,c ...
- android Containers控件
1.RadioGroup 一组单选框容器 2.ListView 3.GridView 4.ExpandableListView 可折叠列表 5.ScrollView 上下滚动条 6.Horizonta ...