下面的案例是C/S结构,既编写客户端有编写服务端而且没有用到http协议

对于B/S结构,我们只需要编写服务器,不需要写客户端。

服务端和单客户端通信

注意事项:如果服务端或者客户端采用read() 一个字节这种读取数据,只要另一方没有关闭连接,read是永远读取不到-1,会陷入死循环中;

解决方法:加上一个判断,程序员自己跳出循环,比如在while循环中,加上

if(strbuilder.indexOf("\n") > 0){//存在消息结束标志
break;
}

服务端代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket; public class Server {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
System.out.println("客户端连接成功:"+server.getInetAddress().getHostAddress()); BufferedReader bufRead = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = bufRead.readLine();
System.out.println("message="+s); BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufwrite.write("你好我是服务端\n");
bufwrite.flush(); bufwrite.close();
bufRead.close(); } catch (IOException e) {
e.printStackTrace();
}
}
} 

客户端代码

import java.io.*;
import java.net.Socket; public class client {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",8080);
BufferedWriter bufWrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//如果服务器使用readline来读取数据,那么发送的数据后面必须加上\n;
bufWrite.write("你好我是客户端\n");
bufWrite.flush(); //PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
//ps.println("dddd");
//ps.flush(); BufferedReader bufread = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bufread.readLine()); //ps.close();
bufWrite.close();
bufread.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

服务器和多客户端通信

即采用多线程的方式进行处理任务

服务端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Server {
public static void main(String[] args) {
try {
ExecutorService es = Executors.newFixedThreadPool(4);
ServerSocket server = new ServerSocket(8080);
while (true){
Socket socket = server.accept();
System.out.println("有客户端连接");
es.execute(new ServerHandle(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
} class ServerHandle implements Runnable{
private Socket socket;
public ServerHandle(Socket socker){
this.socket = socker;
}
@Override
public void run() {
BufferedReader bufRead = null;
try {
bufRead = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
char[] chars = new char[1024];
StringBuilder strbuilder = new StringBuilder();
int len=-1;
while ((len=bufRead.read(chars))!=-1){
strbuilder.append(new String(chars),0,len);
if(strbuilder.indexOf("\n") > 0){//存在消息结束标志
break;
}
}
System.out.println("message="+ strbuilder);
BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufwrite.write("已经收到你的信息:"+strbuilder+"\n");
bufwrite.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}

客户端

import java.io.*;
import java.net.Socket;
import java.util.Scanner; public class client {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",8080);
BufferedWriter bufWrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//如果服务器使用readline来读取数据,那么发送的数据后面必须加上\n;
Scanner input = new Scanner(System.in);
System.out.println("输入一个发送的信息");
String x = input.next();
bufWrite.write(x+"\n");
bufWrite.flush(); BufferedReader bufread = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bufread.readLine()); bufWrite.close();
bufread.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

多客户端之间的通信

Server端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Server {
public static void main(String[] args) {
//保存所有的处理 用户请求连接的 线程
Vector<UserRequestHandle> vector = new Vector<>();
ExecutorService es = Executors.newFixedThreadPool(4);
try {
ServerSocket server = new ServerSocket(8080);
System.out.println("服务器已经启动.......");
while (true){
Socket socket = server.accept();
UserRequestHandle user = new UserRequestHandle(socket,vector);
vector.add(user);
es.execute(user);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} class UserRequestHandle implements Runnable{
private String name;//客户端的名字(唯一),可以绑定用户对象(唯一);
private ObjectInputStream ois;
private ObjectOutputStream oos;
private Socket socket;
private Boolean flag=true;
private Vector<UserRequestHandle> verctor;
public UserRequestHandle(Socket socket,Vector<UserRequestHandle> verctor){
this.socket = socket;
this.verctor = verctor;
}
@Override
public void run() {
try {
ois = new ObjectInputStream(socket.getInputStream());
oos = new ObjectOutputStream(socket.getOutputStream());
while (flag){
Message message = (Message) ois.readObject();
int mes = message.getType();
switch (mes){
case MessageType.type_login:{
name = message.getFrom(); //表示给当前的线程取一个名字;
message.setMessage("欢迎登录"+message.getFrom());
oos.writeObject(message);
break;
}
case MessageType.type_send:{
String to_user = message.getTo();
String to_user_message = message.getMessage();
for (int i = 0; i < verctor.size(); i++) {
if (verctor.get(i).name==null|to_user==null){
continue;
}
if (verctor.get(i).name.equals(to_user)&&!to_user.equals(this.name)){
System.out.println("消息已经正在发送给对方.....");
message.setFrom(name);
message.setMessage(to_user_message);
verctor.get(i).oos.writeObject(message);
break;
}
}
} }
}
ois.close();
oos.close();
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
return;
}catch (Exception e){
}
}
}

 客户端

import java.io.*;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class client {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try {
Socket socket = new Socket("127.0.0.1",8080);
System.out.println("连接服务器成功......");
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//第一步先登录;
System.out.println(MessageType.type_login+","+MessageType.type_send);
System.out.println("输入用户名");
String name = input.next();
oos.writeObject(new Message(name,null,MessageType.type_login,null));
Message message = (Message) ois.readObject();
System.out.println(message.getMessage()); //创建一个单线程从socket中循环取出消息(只读)
ExecutorService receve_message = Executors.newSingleThreadExecutor();
receve_message.execute(new ReceveMessage(ois)); //不断给服务发送消息(只写)
while (true){
System.out.println("输入要发送消息的用户名");
String to_user = input.next();
System.out.println("输入消息");
String to_user_message = input.next();
oos.writeObject(new Message(name,to_user,MessageType.type_send,to_user_message));
} } catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} class ReceveMessage implements Runnable{
private ObjectInputStream ois;
public ReceveMessage(ObjectInputStream ois){
this.ois = ois;
}
@Override
public void run() {
try {
while (true){
Message message = (Message) this.ois.readObject();
System.out.println("["+message.getFrom()+"]"+":"+message.getMessage());
} } catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

message信息对象

import java.io.Serializable;

public class Message implements Serializable {
private String from; //发送消息的人(以后可以用ip来处理)
private String to; //发送消息给谁(以后可以用ip来处理)
private int type; //int type 消息的类型(是登录还是进行消息的发送)
private String message;//消息的内容
public Message(String from, String to, int type, String message) {
this.from = from;
this.to = to;
this.type = type;
this.message = message;
}
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public int getType() {
return type;
}
public String getMessage() {
return message;
}
public void setFrom(String from) {
this.from = from;
}
public void setTo(String to) {
this.to = to;
}
public void setMessage(String message) {
this.message = message;
}
}

MessageType表示配置文件

public class MessageType {
public static final int type_login = 1;//消系中有type_login表示需要登录
public static final int type_send = 2; //消息中有type_send表示该消息为发送
}

TCP聊天室原理

服务器用于转发消息

客户端和服务器建立一个socket连接

客户端将socker交给两个线程处理,一个线程(可以使用主线程)用来接收服务端的数据,一个线程用来发送数据

服务端接收到一个连接请求,就开启1个线程来处理请求,并将socker添加到列表中这个列表可以被每一个线程共享,当线程接收到数据后,就遍历列表,对每一个socker进行发送数据(可以选择不给自己发送数据,!=this)。

TCP私聊

我们之前已经封装好了一个socker列表,当某一个客户端发送数据@xx:你好,我们可以截取xx,在发送数据的时候如果数据中有@符号,就给某一个socker发送数据。

注意我们可以封装一个socker连接对象,里面传入socker,name,并且封装send(),recive()方法,将这个封装对象add到列表中。

UDP服务端和客户端通信

UDP没有严格意义上的服务端

服务端

public class Server {
public static void main(String[] args) throws IOException {
//UDP协议要求包小于64K,我们用500个字节数组来接受数据,如果发送的数据大于500个字节,超过500字节的数据接受不到
byte[] bs = new byte[500];
//准备容器,用这个容器来接受客户端发送的数据
DatagramPacket p1 = new DatagramPacket(bs, bs.length);
//创建数据报套接字
DatagramSocket socket_B = new DatagramSocket(10010);
//接收数据报包
socket_B.receive(p1);
System.out.println(new String(bs, 0, p1.getLength())); byte[] send_msg = "我是服务端,我已经收到你的消息".getBytes();
InetAddress desIp = p1.getAddress(); //获取对方的ip
int dedport = p1.getPort();
//数据包中包括数据,数据长度,对方的ip和绑定的端口
DatagramPacket p = new DatagramPacket(send_msg, send_msg.length, desIp, dedport);
socket_B.send(p);
socket_B.close();
}
}

客户端

public class Client {
public static void main(String[] args) throws IOException {
byte[] send_bs = "我是客户端,我给你发送了一些数据".getBytes();//要发的信息内容
//创建数据报,里面包括 数据和数据长度 对方的ip地址 和 对方的端口,
DatagramPacket p1 = new DatagramPacket(send_bs, send_bs.length, InetAddress.getByName("127.0.0.1"),10010);
//创建数据报套接字,绑定端口
DatagramSocket socket = new DatagramSocket(8080);
socket.send(p1); //用数组接收数据报包
byte[] rece_msg = new byte[500];
DatagramPacket p = new DatagramPacket(rece_msg, rece_msg.length);
socket.receive(p);//数据量如果多,可以使用while循环
System.out.println(new String(rece_msg, 0, p.getLength()));
//关闭套接字
socket.close();
}
}

udp实现双向发送数据

服务端(客户端)和客户端都必须开2个线程,一个线程用于发送数据,System.in堵塞该线程,一个线程等待对方发送数据,receive()堵塞该线程

  

一个简单的B/S架构服务器

http协议(应用层传输协议)

  首先tcp/udp协议,只能保证数据的发送,服务器(客户端)通过tcp可以获取客户端(服务器)发送的消息,但是如果来解析这些数据呢,这就需要一个标准的协议,并且全世界都必须遵循。这个协议(http),规定了服务器和客户端发送数据的格式。接受方有安装标准协议来解析这些数据,获得有用的信息。

  现在浏览器会安装http协议通过tcp发送一段特殊的格式的数据,你的服务器就需要按照http协议的格式来解析这些数据,而服务器发送给浏览器的数据,浏览器只会按照http标准格式数据解析。所以我们发送的数据必须按照http格式要求写。

  当然如果你可以单独开发一款浏览器,这个浏览器访问你的服务器,你想怎么定协议就怎么定协议。只要你的服务器和浏览器可以解析正确的数据就行,你也可以将你解析数据的方式,和方式数据的格式定义你的协议。这就是应用层协议。

请求协议

请求行:方法(GET/POST)、URI、协议/版本
请求头:Request Header
请求正文
1、请求行
  GET /index.htm1?name=xx HTTP/1.1
2、请求体
  Accept:text/html,application/xhtml+xml,*/*
  Accept-Language:zh-CN
  User-Agent:Mozilla/5.0(compatible;MSIE 9.0;W indows NT 6.1;Trident/5.0)
  Accept-Encoding:ggip,deflate
  Host:localhost
  Connection:Keep-Alive
3、请求正文

响应协议

状态行:协议/版本、状态码,转态描述
响应头(Response Header)
响应正文
1、状态行
HTTP/1.0 2000K
2、请求头:
  Date:Mon,31Dec209904:25:57GMT
  Server:shsxt Server/0.0.1;charset=GBK
  Content-type:text/html
  Content-length:397254263
请求正文(注意与请求头之间有个空行)   xxxx

  

服务器

public class Server {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
System.out.println("客户端连接成功:"+server.getInetAddress().getHostAddress()); BufferedReader bufRead = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = bufRead.readLine();
System.out.println("message="+s); BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufwrite.write("HTTP 1.1\r\n\r\n<h1>xx</h1>");
bufwrite.flush(); bufwrite.close();
bufRead.close(); } catch (IOException e) {
e.printStackTrace();
}
}
}

java web----TCP/DUP 通信的更多相关文章

  1. java web 数据库开发1

    一个完整的数据库部署架构通常由客户端和服务器端两部分组成.客户端封装数据库请求将其发送给服务器端,服务器端执行完毕将其及结果返回给服务器端. 以mysql为例 介绍java应用程序对数据库的访问 JD ...

  2. 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)(转)

    书上示例 在第一章<基本套接字>中,作者给出了一个TCP Socket通信的例子——反馈服务器,即服务器端直接把从客户端接收到的数据原原本本地反馈回去. 书上客户端代码如下: 1 2 3 ...

  3. 第4章 TCP/IP通信案例:访问Internet上的Web服务器

    第4章 TCP/IP通信案例:访问Internet上的Web服务器 4.2 部署代理服务器 书中为了演示访问Internet上的Web服务器的全过程,使用了squid代理服务器程序模拟了一个代理服务器 ...

  4. 实验09——java基于TCP实现客户端与服务端通信

    TCP通信         需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手        底层通过 流 发送数据 数据没有大小限制        可靠的传输机制 - 丢包重发 包的顺序的 ...

  5. 《java入门第一季》之Socket编程通信和TCP协议通信图解

    Socket编程通信图解原理: TCP协议通信图解

  6. Java Web高性能开发(二)

    今日要闻: 性价比是个骗局: 对某个产品学上三五天个把月,然后就要花最少的钱买最多最好的东西占最大的便宜. 感谢万能的互联网,他顺利得手,顺便享受了智商上的无上满足以及居高临下的优越感--你们一千块买 ...

  7. 认识Java WEB应用

    JavaWeb应用概念 在Sun的JavaServlet规范中,对Java Web应用作了这样定义:JAVA Web应用由一组Servlet.HTML页.类.以及其它可以被绑定的资源构造.它可以在各种 ...

  8. Java Web 高性能开发,第 2 部分: 前端的高性能

    Web 发展的速度让许多人叹为观止,层出不穷的组件.技术,只需要合理的组合.恰当的设置,就可以让 Web 程序性能不断飞跃.Web 的思想是通用的,它们也可以运用到 Java Web.这一系列的文章, ...

  9. 第一章 Java Web工作原理

    一:在本章我们将学到如下的内容 >HTTP协议原理 >服务器端Web编程原理 >Servlet与Web容器 >Java Web应用程序的组成 >Tomcat介绍 一:1. ...

  10. Java Web 高性能开发,前端的高性能

    Java Web 高性能开发,第 2 部分: 前端的高性能 Web 发展的速度让许多人叹为观止,层出不穷的组件.技术,只需要合理的组合.恰当的设置,就可以让 Web 程序性能不断飞跃.Web 的思想是 ...

随机推荐

  1. 剑指Offer题解索引

    数组 数组中重复的数字 二维数组中的查找 构建乘积数组 字符串 替换空格 字符流中第一个不重复的字符 表示数值的字符串 递归和循环 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 链表 从尾到头打印链表 ...

  2. Python 20 Ajax全套

    概述 对于web应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要 ...

  3. 2017-2018-2 20165237 实验四《Android开发基础》实验报告

    2017-2018-2 20165237 实验四<Android开发基础>实验报告 实验报告表头: No.1 实验要求: Android程序设计-1 实验要求: 参考<Java和An ...

  4. android SeekBar设置背景无法被填充满的bug

    在做一个播放进度的时候,用到了SeekBar,调用布局如下: <SeekBar android:id="@+id/example_audio_bar" android:lay ...

  5. Matlab 读取 ROS bag 文件指定消息数据

    近期在接触Ros的时候遇到了一些问题,如何将rosbag中的信息提取出来进行进一步处理呢? 如三维点位置信息,视频信息(如果有的话)等等. 我采用的是MATLAB 读取bag信息 filepath=f ...

  6. SpringCloud Config(分布式配置中心)

    ⒈是什么? Spring Cloud Config分为服务端和客户端两部分. 服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信心等接口. ...

  7. Python代码打印出9*9 九九乘法表

    九九乘法表 一一 小问题展现技术 1.示例一 for i in range(10): s='' for j in range(1,i+1): s+=str(j)+'*'+str(i)+'='+str( ...

  8. pyinstaller 打包exe可执行文件

    Python打包EXE方法之一 一.安装Pyinstaller 1.安装pywin32 下载安装文件:查找到跟自己适用的python版本及window系统版本匹配的pywin32,下载后安装 使用pi ...

  9. DAC杂谈一

    DAC种类: 有权电阻网络DAC 输出电压变化范围为:0~-(2^n-1)/2^n*Vref 当位数很高时,每个电阻都有很高精度是十分困难的. 倒T型电阻网络DAC(比如AD7520 10bit 已停 ...

  10. 《Debug Hacks》和调试技巧【转】

    转自:https://blog.csdn.net/sdulibh/article/details/46462529 Debug Hacks 作者为吉冈弘隆.大和一洋.大岩尚宏.安部东洋.吉田俊辅,有中 ...