下面的案例是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. python概念(一)python基本数据类型

    http://www.cnblogs.com/nulige/p/6115765.html

  2. G - Intersecting Rectangles Kattis - intersectingrectangles (扫描线)(判断多个矩形相交)

    题目链接: G - Intersecting Rectangles Kattis - intersectingrectangles 题目大意:给你n个矩形,每一个矩形给你这个矩形的左下角的坐标和右上角 ...

  3. Maven项目在更新过程停止,再更新无效-->解决

    ---类似网友问题:但我按照这样无法解决. eclipse中maven项目jar包不会自动下载解决办法 - wavemelody - 博客园http://www.cnblogs.com/mymelod ...

  4. 由JDBC而来的对Class.forName()用法发散

    昨日在帮一个学习java的小伙子指导JDBC链接数据库时,在对数据库驱动进行加载时,用到Class.forName(),一直都是照葫芦画瓢,对这种写法一直不是太理解,故查询了相关文档后,将心得记录一下 ...

  5. 一次悲催的nginx转发白屏经历

    背景 公司还有一个学习平台,由于公网地址问题,所以想用nginx转发一下,首先后端地址访问时没有问题的,一切正常. 用nginx转发后,访问nginx代理地址悲催了,出现了白屏. 排查过程 首先贴出来 ...

  6. C# 事务 四种事务隔离级别

    http://www.zsythink.net/archives/1233 不同隔离级别的问题   脏读(Dirty Read) 一个事务处理过程里读取了另一个未提交的事务中的数据 例子: 当一个事务 ...

  7. Linux内核很吊之 module_init解析 (下)【转】

    转自:https://blog.csdn.net/richard_liujh/article/details/46758073 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...

  8. Python运维开发基础08-文件基础【转】

    一,文件的其他打开模式 "+"表示可以同时读写某个文件: r+,可读写文件(可读:可写:可追加) w+,写读(不常用) a+,同a(不常用 "U"表示在读取时, ...

  9. Awk 命令学习总结、AWk命令系列学习(linux shell)

    AWK基本语法 下面没有提到awk命令怎么使用了,你可以通过 运行:awk –h 查询到所有命令及参数!下面把awk作为一门语言分节介绍. linux awk 内置变量使用介绍   awk语言中,怎么 ...

  10. C++ 读取字符串中的数字

    今天真是试了各种方法,笨方法聪明方法都有了 方法1:一个字符一个字符的读取 方法2:借助strtok实现split 适用于char 方法3:借助istringstream实现split 适用于stri ...