创建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客户服务端的更多相关文章

  1. 利用select实现IO多路复用TCP服务端

    一.相关函数 1.  int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeva ...

  2. TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端

    目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的使用 框架源码结构 补充说明 源码地址 说明 之前有好几篇博客在讲TCP/UDP通信方 ...

  3. Java网络编程(TCP服务端)

    /* * TCP服务端: * 1.创建服务端socket服务,并监听一个端口 * 2.服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象 * 3.可以通过获 ...

  4. Java TCP服务端向客户端发送图片

    /** * 1.创建TCP服务端,TCP客户端 * 2.服务端等待客户端连接,客户端连接后,服务端向客户端写入图片 * 3.客户端收到后进行文件保存 * @author Administrator * ...

  5. TCP服务端开发为例--web开发不同url请求走不同control方法

    拿java的web开发为例子,相信有很多小伙伴是做j2EE开发的,htpp请求,json数据传输都是工作中经常用的,查询请求,添加请求,修改请求前端配个url,例如https://localhost/ ...

  6. 03-案例——多任务版TCP服务端程序开发

    案例——多任务版TCP服务端程序开发   1. 需求     目前我们开发的TCP服务端程序只能服务于一个客户端,如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢?完成多任务,可以使用线程 ...

  7. Asp.Net项目与TCP服务端交互

    private void SocketSend(string sendstr) { //将字符串转换成字节数组 Byte[] fsSize = System.Text.Encoding.Default ...

  8. 【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端

    [转]TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP ...

  9. python创建tcp服务端和客户端

    1.tcp服务端server from socket import * from time import ctime HOST = '' PORT = 9999 BUFSIZ = 1024 ADDR ...

随机推荐

  1. [luoguP2051] [AHOI2009]中国象棋(DP)

    传送门 注释写明了一切 #include <cstdio> #define N 111 #define p 9999973 #define LL long long int n, m; L ...

  2. BZOJ 1297: [SCOI2009]迷路 [矩阵快速幂]

    Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同 ...

  3. AXMLPrinter2.jar反编译xml文件

    apk里的AndroidManifest.xml 为二进制文件,可通过AXMLPrinter2.jar包反编译出来 cmd命令行运行一下命令: java -jar AXMLPrinter2.jar A ...

  4. 生成PDF文档

    byte[] buffer = context.Response.Clear(); context.Response.ClearHeaders(); context.Response.ClearCon ...

  5. 洛谷——P2298 Mzc和男家丁的游戏

    P2298 Mzc和男家丁的游戏 题目背景 mzc与djn的第二弹. 题目描述 mzc家很有钱(开玩笑),他家有n个男家丁(做过上一弹的都知道).他把她们召集在了一起,他们决定玩捉迷藏.现在mzc要来 ...

  6. HNOI_2002 营业额统计(Splay)

    此题可以用STL的multiset解决,也可以手打一棵伸展树(Splay)来求前驱与后驱. 使用multiset: #include<iostream> #include<set&g ...

  7. 转:C#并口热敏小票打印机打印位图

    最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: class LptControl { private s ...

  8. android中MVC,MVP和MVVM三种模式详解析

    我们都知道,Android本身就采用了MVC模式,model层数据源层我们就不说了,至于view层即通过xml来体现,而 controller层的角色一般是由activity来担当的.虽然我们项目用到 ...

  9. wamp配置虚拟域名

    1.打开apache下httpd.conf 我的目录是在F:\wamp\bin\apache\apache2.2.22\conf\httpd.conf 2.去掉这两行前面的#注释 LoadModule ...

  10. sqlite学习笔记10:C语言中使用sqlite之查询和更新数据

    前面说到的 sqlite_exec() 中的第三个參数, SQLite 将为 sql 參数内运行的每一个 SELECT 语句中处理的每一个记录调用这个回调函数. 本节加入了两个函数.selectFro ...