全部代码

直接使用socket

客户端

import java.io.*;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket; public class Client {
public static void main(String[] args)throws IOException {
Socket socket=new Socket();
//超时时间
socket.setSoTimeout(3000);
//连接本地端口8080,超时时间2000ms
socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(),8080),3000);
System.out.println("已发起服务器连接并进入后续流程~");
System.out.println("客户端信息:"+socket.getLocalAddress()+" P:"+socket.getLocalPort());
System.out.println("服务端信息:"+socket.getInetAddress()+" P:"+socket.getPort());
try{
//发送接受数据
todo(socket);
}catch (Exception e){
System.out.println("异常关闭");
}
socket.close();
System.out.println("客户端已退出~"); }
private static void todo(Socket client) throws IOException{
//构建键盘输入流
InputStream in=System.in;
BufferedReader input=new BufferedReader(new InputStreamReader(in)); //socket输出流,并转换为打印流
OutputStream outputStream=client.getOutputStream();
PrintStream socketPrintStream=new PrintStream(outputStream); //得到Socket输入流,并转换为BufferReader
InputStream inputStream=client.getInputStream();
BufferedReader socketBufferedReader=new BufferedReader(new InputStreamReader(inputStream)); boolean flag=true;
do {
//键盘读取一行
String str =input.readLine(); //发送到服务器
socketPrintStream.println(str); //从服务器读取一行
String echo = socketBufferedReader.readLine();
if ("bye".equalsIgnoreCase(echo)) {
flag = false;
}
else
{
System.out.println(echo);
}
}
while (flag); //资源释放
socketPrintStream.close();
socketBufferedReader.close();
}
}

服务端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket; public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(8080); System.out.println("服务器准备就绪~");
System.out.println("服务器信息:"+server.getInetAddress()+" P:"+server.getLocalPort()); for( ;;) {
//等待客服端连接
Socket client = server.accept();
ClientHandler clientHandler = new ClientHandler(client);
clientHandler.start();
}
}
/*
客户端消息处理
*/
private static class ClientHandler extends Thread{
private Socket socket;
private boolean flag=true;
ClientHandler(Socket socket)
{
this.socket=socket; } @Override
public void run() {
super.run();
System.out.println("新客户端连接:"+socket.getInetAddress()+" P:"+socket.getLocalPort()); try{
//得到打印流,用于数据输出;服务器回送数据
PrintStream socketOutput=new PrintStream(socket.getOutputStream());
//得到输入流,用于接受数据
BufferedReader socketInput =new BufferedReader(new InputStreamReader(
socket.getInputStream()));
do {
//客户端拿到一条数据
String str=socketInput.readLine();
if("bye".equalsIgnoreCase(str))
{
flag=false;
//回送
socketOutput.println("bye");
}
else
{
System.out.println(str);
socketOutput.println("回送:"+str.length());
}
}while(flag);
socketInput.close();
socketOutput.close();
}catch (Exception e) {
System.out.println("连接异常断开");
}finally {
//连接关闭
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("客户端已关闭"+socket.getInetAddress()+" P:"+socket.getLocalPort());
}
}
}

使用UDP

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket; /*
UDP提供者,用于提供服务
*/
public class UDPProvider {
public static void main(String[] args) throws IOException {
System.out.println("UDPProvider Started.");
//作为接收者,指定一个端口用于数据接收
DatagramSocket ds=new DatagramSocket(20000); //构建接收实体
final byte[] buf=new byte[512]; DatagramPacket receivePack=new DatagramPacket(buf,buf.length); //接收
ds.receive(receivePack); //打印接收到的信息与发送者的信息
//发送者的IP地址
String ip=receivePack.getAddress().getHostAddress();
int port=receivePack.getPort();
int dataLen=receivePack.getLength();
String data=new String(receivePack.getData(),0,dataLen);
System.out.println("UDPProvider receive form IP: +ip" +
"\tPort"+port +"\tData:"+data);
//构建一份回送数据
String responseData="Receive data with len"+dataLen;
byte[] responseDataBytes=responseData.getBytes();
//直接根据发送者构建一份回送信息
DatagramPacket respnsePacket= new DatagramPacket(responseDataBytes,
responseDataBytes.length,
receivePack.getAddress(),
receivePack.getPort()
);
ds.send(respnsePacket);
//完成
System.out.println("UDPProvider Finished.");
ds.close(); }
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress; /*
UDP提供者,用于提供服务
*/
public class UDPSearcher {
public static void main(String[] args) throws IOException {
System.out.println("UDPSearcher Started.");
//作为搜素者,无需指定端口
DatagramSocket ds=new DatagramSocket();
//构建一份请求数据
String resquestData="Hello world!";
byte[] resquestDataBytes=resquestData.getBytes();
DatagramPacket resquestPacket= new DatagramPacket(resquestDataBytes,
resquestDataBytes.length
);
//本机20000端口
resquestPacket.setAddress(InetAddress.getLocalHost());
resquestPacket.setPort(20000);
//发送
ds.send(resquestPacket);
//构建接收实体
final byte[] buf=new byte[512]; DatagramPacket receivePack=new DatagramPacket(buf,buf.length); //接收
ds.receive(receivePack); //打印接收到的信息与发送者的信息
//发送者的IP地址
String ip=receivePack.getAddress().getHostAddress();
int port=receivePack.getPort();
int dataLen=receivePack.getLength();
String data=new String(receivePack.getData(),0,dataLen);
System.out.println("UDPSearcher receive form IP: +ip" +
"\tport"+"Port:"+port +"\tdata:"+data); //完成
System.out.println("UDPSearcher Finished.");
ds.close(); }
}

使用SN

public class MessageCreator {
private static final String SN_HEADER="收到暗号,我是(SN):";
private static final String PORT_HEADER="这是暗号,请回电口(Port)"; public static String buildWithPort(int port){
return PORT_HEADER+port;
}
public static int parsePort(String data){
if(data.startsWith(PORT_HEADER)){
return Integer.parseInt(data.substring(PORT_HEADER.length()));
}
return -1;
} public static String buildWithSn(String sn){
return SN_HEADER+sn;
}
public static String parseSN(String data){
if(data.startsWith(SN_HEADER)){
return data.substring(SN_HEADER.length());
}
return null;
}
}

根据上面写的能运用的局域网搜索

public class MessageCreator {
private static final String SN_HEADER="收到暗号,我是(SN):";
private static final String PORT_HEADER="这是暗号,请回电。口(Port)"; public static String buildWithPort(int port){
return PORT_HEADER+port;
}
public static int parsePort(String data){
if(data.startsWith(PORT_HEADER)){
return Integer.parseInt(data.substring(PORT_HEADER.length()));
}
return -1;
} public static String buildWithSn(String sn){
return SN_HEADER+sn;
}
public static String parseSN(String data){
if(data.startsWith(SN_HEADER)){
return data.substring(SN_HEADER.length());
}
return null;
}
}
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch; /*
UDP提供者,用于提供服务
*/
public class UDPSearcher {
private static final int LISTEN_PORT=30000;
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("UDPSearcher Started.");
Listener listener=listen();
sendBroadCast();
//读取任意键盘信息可以退出
System.in.read();
List<Device> devices=listener.getDevicesAndClose();
for(Device device:devices){
System.out.println("Device"+device.toString());
}
//完成
System.out.println("UDPSearcher Finished"); }
private static Listener listen() throws InterruptedException {
System.out.println("UDPSearcher start listen.");
CountDownLatch countDownLatch=new CountDownLatch(1);
Listener listener=new Listener(LISTEN_PORT,countDownLatch);
listener.start(); countDownLatch.await();
return listener;
}
private static void sendBroadCast() throws IOException {
System.out.println("UDPSearcher sendBroadCast Started.");
//作为搜素者,无需指定端口
DatagramSocket ds=new DatagramSocket();
//构建一份请求数据
String resquestData=MessageCreator.buildWithPort(LISTEN_PORT);
byte[] resquestDataBytes=resquestData.getBytes();
DatagramPacket resquestPacket= new DatagramPacket(resquestDataBytes,
resquestDataBytes.length
);
//本机20000端口
resquestPacket.setAddress(InetAddress.getByName("255.255.255.255"));
resquestPacket.setPort(20000);
//发送
ds.send(resquestPacket);
ds.close(); //完成
System.out.println("UDPSearcher sendBroadCast Finished.");
}
private static class Device{
final int Port;
final String ip;
final String sn; public Device(int port, String ip, String sn) {
Port = port;
this.ip = ip;
this.sn = sn;
} @Override
public String toString() {
return "Device{" +
"Port=" + Port +
", ip='" + ip + '\'' +
", sn='" + sn + '\'' +
'}';
}
}
private static class Listener extends Thread{
private final int listenPort;
private final CountDownLatch countDownLatch;
private final List<Device> devices=new ArrayList<>();
private boolean done=false;
private DatagramSocket ds=null;
public Listener(int listenPort, CountDownLatch countDownLatch){
super();
this.listenPort = listenPort;
this.countDownLatch = countDownLatch;
}
@Override
public void run(){
super.run();
System.out.println("UDPSearcher started");
//通知已启动
countDownLatch.countDown();
try{
//监听端口
ds=new DatagramSocket(listenPort);
while(!done){ //构建接受实体
final byte[] buf=new byte[512]; DatagramPacket receivePack=new DatagramPacket(buf,buf.length); //接收
ds.receive(receivePack); //打印接收到的信息与发送者的信息
//发送者的IP地址
String ip=receivePack.getAddress().getHostAddress();
int port=receivePack.getPort();
int dataLen=receivePack.getLength();
String data=new String(receivePack.getData(),0,dataLen);
System.out.println("UDPProvider receive from IP:" +ip +
"\tPort"+port +"\tData:"+data); String sn=MessageCreator.parseSN(data);
if(sn!=null){
Device device=new Device(port,ip,sn);
devices.add(device);
} }
}catch (Exception ignored) { }finally {
close();
}
System.out.println("UDPProvider Searcher stoped");
}
private void close(){
if(ds!=null){
ds.close();
ds=null;
}
}
List<Device>getDevicesAndClose(){
done=true;
close();
return devices;
} } }
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.UUID; /*
UDP提供者,用于提供服务
*/
public class UDPProvider {
public static void main(String[] args) throws IOException {
//生成唯一标示
String sn= UUID.randomUUID().toString();
//构建线程,启动线程
Provider provider=new Provider(sn);
provider.start();
//读取键盘信息后可以退出
System.in.read();
provider.exit();
}
private static class Provider extends Thread{
private final String sn;
private boolean done=false;
private DatagramSocket ds=null;
public Provider(String sn){
super();
this.sn=sn;
} @Override
public void run() {
super.run();
System.out.println("UDPProvider Started.");
try {
//监听20000端口
ds = new DatagramSocket(20000);
while (!done) {
//构建接收实体
final byte[] buf = new byte[512]; DatagramPacket receivePack = new DatagramPacket(buf, buf.length);
//接收
ds.receive(receivePack);
//打印接收到的信息与发送者的信息
//发送者的IP地址
String ip = receivePack.getAddress().getHostAddress();
int port = receivePack.getPort();
int dataLen = receivePack.getLength();
String data = new String(receivePack.getData(), 0, dataLen);
System.out.println("UDPProvider receive from IP:" +ip +
"\tPort" + port + "\tData:" + data);
//解析端口号
int responsePort=MessageCreator.parsePort(data);
if(responsePort!=-1) {
//构建一份回送数据
String responseData = MessageCreator.buildWithSn(sn);
byte[] responseDataBytes = responseData.getBytes();
//直接根据发送者构建一份回送信息
DatagramPacket responsePacket = new DatagramPacket(responseDataBytes,
responseDataBytes.length,
receivePack.getAddress(),
responsePort
);
ds.send(responsePacket);
}
}
} catch (Exception ignored) { } finally {
close();
}
} private void close(){
if(ds!=null) {
ds.close();
ds=null;
}
} void exit(){
done=true;
close();
}
}
}

服务器可以做HTTP的代理

2MSL
        当TCP执行主动关闭,并发出最后一个ACK,该链接必须在TIME_WAIT状态下停留的时间为2MSL。这样可以(1)让TCP再次发送最后的ACK以防这个ACK丢失(被动关闭的一方超时并重发最后的FIN);保证TCP的可靠的全双工连接的终止。(2)允许老的重复分节在网络中消失。参考文章《unix网络编程》(3)TCP连接的建立和终止 在TIME_WAIT状态 时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置 SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

TCP/IP 协议栈学习代码的更多相关文章

  1. TCP/IP协议学习(五) 基于C# Socket的C/S模型

    TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的:然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多.C#通过提供的Socket API ...

  2. C1000k 新思路:用户态 TCP/IP 协议栈

    现在的服务器支撑上百万个并发 TCP 连接已经不是新闻(余锋2010年的演讲,ideawu 的 iComet 开源项目,WhatsApp 做到了 2.5M).实现 C1000k 的常规做法是调整内核参 ...

  3. TCP/IP协议学习(四) 协议概述

    生活中有舒适区,借口成为懒惰的护身符,学习也有舒适区,逃避便是阻止进步的最大障碍. 经过半年多嵌入式方面的工作和学习,我提高了很多,但同时我也对自己所面临的问题逐渐清晰: 1. 偏于实践,理论基础不牢 ...

  4. TCP/IP协议学习之实例ping命令学习笔记

    TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...

  5. 用virtualbox+模拟串口+CDT调试linux内核 TCP/IP协议栈-起步

    经常有人问一台机器如何将hello经网络发送给另一台机器,我确实是不知道,只能看代码了. 说明:本人对内核的研究学习也是刚刚起步,有很多不了解的,所以文中可能会有一些"一本正经的胡扯&quo ...

  6. 几种开放源码的TCP/IP协议栈比较

    http://blog.chinaunix.net/uid-28785506-id-3828286.html 原文地址:几种开放源码的TCP/IP协议栈比较 作者:三点水兽 1.BSD TCP/IP协 ...

  7. 几个主流TCP/IP协议栈介绍

    我们知道TCP IP协议栈内包括了诸多协议.那么对于这当中的协议的功能以及作用,我们来具体了解一下吧.现在让我们做一个盘点,帮助大家总结一下,还望对大家能够有所帮助. 1.BSD TCP IP协议栈 ...

  8. TCP/IP协议学习(六) 链路层详解

    学习知识很简单,但坚持不懈却又是如此的困难,即使一直对自己说"努力,不能停下"的我也慢慢懈怠了... 闲话不多说,本篇将讲述TCP/IP协议栈的链路层.在本系列第一篇我讲到,TCP ...

  9. [转]为何TCP/IP协议栈设计成沙漏型的

    http://m.blog.csdn.net/blog/dog250/18959371 前几天有人回复我的一篇文章问,为何TCP/IP协议栈设计成沙漏型的.这个问题问得好!我先不谈为何它如此设计,我一 ...

随机推荐

  1. 第五章 Odoo 12开发之导入、导出以及模块数据

    大多数Odoo 模块的定义,如用户界面和安全规则,实际是存储在对应数据表中的数据记录.模块中的 XML 和 CSV 文件不是 Odoo 应用运行时使用,而是载入数据表的手段.正是因为这个原因,Odoo ...

  2. memcpy 和 memmove

    memcpy 原形为: void *memcpy(void *dest, const void *src, size_t n); 其用于内存空间的拷贝,但是并没有考虑内存重叠问题. memmove原形 ...

  3. Maven实战04_使用Archetype生成项目骨架

    在上一章中的HelloWorld中,我们的项目遵循了一些Maven项目的约定 在项目的根目录中放置pom.xml 在src/main/java目录中放置项目的主代码 在src/test/java目录中 ...

  4. 在window下远程虚拟机(centos)hadoop运行mapreduce程序

    (注:虽然连接成功但是还是执行不了.以后有时间再解决吧 看到的人别参考仅作个人笔记)先mark下 1.首先在window下载好一个eclipse.和拷贝好linux里面hadoop版本对应的插件(我是 ...

  5. Leetcode221. Maximal Square最大正方形

    在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积. 示例: 输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 输出: 4 方法一 ...

  6. springboot框架实现启动项目执行指定代码

    说明: 当有写代码需要在项目启动时执行的时候(即项目启动完成前),可以使用这个方法. 步骤: 创建一个启动类并在类上打上@Component注解 让这个类实现CommandLineRunner接口 重 ...

  7. [转]深入理解定位父级offsetParent及偏移大小

    偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.offsetTop.offsetHeight.offsetWidth这四个 ...

  8. Git同账号多平台配置

    最近工作中使用到了Git,虽然以前学习过,但是已经忘的差不多了,遂将本次配置过程整理成笔记以备忘 生成公钥 ssh-keygen -t rsa -C "gana10007@163.com&q ...

  9. 提升mysql服务器性能(HA MMM MHA MaxScale)

    原文:提升mysql服务器性能(HA MMM MHA MaxScale) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/detai ...

  10. Django中form组件的is_valid校验机制

    先来归纳一下整个流程(1)首先is_valid()起手,看seld.errors中是否值,只要有值就是flase(2)接着分析errors.里面判断_errors是都为空,如果为空返回self.ful ...