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 ...
随机推荐
- BZOJ 3939 [Usaco2015 Feb]Cow Hopscotch ——线段树 CDQ分治
显然dp[i][j]=ps[i-1][j-1]-sigma(dp[k<i][l<j],a[i][j]=a[k][l]) 考虑对于每一种颜色都开一颗区间线段树,但是空间不够. 所以我们可以动 ...
- USACO Party Lamps
题目大意:一排灯有n个,有4种开关,每种开关能改变一些灯现在的状态(亮的变暗,暗的变亮)现在已知一些灯的亮暗情况,问所以可能的情况是哪些 思路:同一种开关开两次显然是没效果的,那么枚举每个开关是否开就 ...
- getParameter 与 getAttribute的区别
request.getAttribute():是request时设置的变量的值,用request.setAttribute("name","您自己的值");来设 ...
- excel打乱各行的顺序,实现无序随机排列
由于公司做活动,经常会发些激活码过来,为了让激活码能够充分使用,经常要打乱激活码的顺序,百度了下,看了下网上的介绍,还不错,挺实用,记录下来. 具体方法如下: 1.将文本里的内容复制到Excel里的任 ...
- spring boot -- 无法读取html文件,碰到的坑
碰到的坑,无法Controller读取html文件 1. Controller类一定要使用@Controller注解,不要用@RestController 2. resource目录下创建templa ...
- 487. Max Consecutive Ones II
Given a binary array, find the maximum number of consecutive 1s in this array if you can flip at mos ...
- Spring中Bean的后置处理器
以下内容引用自http://wiki.jikexueyuan.com/project/spring/bean-post-processors.html: Bean后置处理器 BeanPostProce ...
- CentOS 5.4 final下Systemtap的安装
CentOS 5.4 final下Systemtap的安装 时间:2015-02-11来源:linux网站 作者:zklth 一.Systemtap运行环境需求 (1)linux kernel ...
- 第21章、OnItemSelectedListener事件(从零开始学Android)
在Android App应用中,OnItemSelectedListener事件也会经常用到,我们一起来了解一下. 基本知识点:OnItemSelectedListener事件 一.界面 1.新建pr ...
- Cocos2d-x JSB 自己主动绑定bindings
Javascript Binding (简称JSB) 自己主动绑定教程. Cocos2d-x JSB 自己主动绑定bindings-generator (以下简称B-G) 使用心得 假设想弄清深入原理 ...