`

socket编程学习笔记

阅读更多

       聊到socket编程,我脑子第一反应就是activeMq、及JMS的其他应用底层都是基于socket实现的,当然我们日常用的QQ、微信等通讯工具也是基于socket实现的(其实我们工作中常用到的log4j底层也用到了socket),由于socket应用面如此广泛、所以我今天翻阅了大量网上资料、并自己写了简单的例子进行学习,下面聊聊我的学习笔记和心得。

       当然在今天学习之前我就有使用过socket进行项目编码的经验了,记得当初在给某一线城市房管局做项目时,档案馆的档案都是基于PDA服务器进行存管的,PDA对外提供了socket服务,所以当初我就用的socket客户端代码去调用PDA服务发起调档的请求。

 

       下面是我11年写的代码,现在贴出来,因为当时档案馆库房很多,每个库房都有socket服务器,所以代码需要通过判断很多规则动态调用不同库房的socket服务器、并与之通讯,发送调档请求。

public boolean socketSendMessage2PDA(String daidUnionStr, int type) {
    log.info("调档发送时给PDA发送调档信息,发送的档案ID字符串为:" + daidUnionStr);
    if (daidUnionStr != null) {
        String[] daidList = daidUnionStr.split(":");
        for (String daid : daidList) {
            TpaDast tpaDast = (TpaDast) this.findEntityById("TpaDast", Long.valueOf(daid));
TpaDawzxx dawzxx = tpaDast.getDawzxx();
List<TpaDaglxxb> glxxbList = this.getDaglxxbListByDabh(tpaDast.getDacode());
            if (dawzxx != null) {
                ConfigService configService = (ConfigService) Framework.getEngine().getContainer().getComponent("configService");
String hostIP = "", cqrxm = "未知";
StringBuffer addressSbf = new StringBuffer();
                if (glxxbList != null && glxxbList.size() > 0) cqrxm = glxxbList.get(0).getCqrxm();
//根据config.properties文件中配置的档案的PDA服务地址
                //1号库房PDA服务器地址
if (dawzxx.getFh() == 1l || dawzxx.getFh().equals(1l)) hostIP = configService.getString("server1_Ip");
//2号库房PDA服务器地址
if (dawzxx.getFh() == 2l || dawzxx.getFh().equals(2l)) hostIP = configService.getString("server2_Ip");
//3号库房PDA服务器地址
if (dawzxx.getFh() == 3l || dawzxx.getFh().equals(3l)) hostIP = configService.getString("server3_Ip");
//4号库房PDA服务器地址
if (dawzxx.getFh() == 4l || dawzxx.getFh().equals(4l)) hostIP = configService.getString("server4_Ip");
//5号库房PDA服务器地址
if (dawzxx.getFh() == 5l || dawzxx.getFh().equals(5l)) hostIP = configService.getString("server5_Ip");
log.info("调用PDA服务器的IP地址为:" + hostIP);
//动态拼接PDA能够识别的位置信息
if (dawzxx.getFh() < 10) addressSbf.append("0").append(dawzxx.getFh());
                else addressSbf.append(dawzxx.getFh());
addressSbf.append(dawzxx.getQh());
                if (dawzxx.getLh() < 10) addressSbf.append("0").append(dawzxx.getLh());
                else addressSbf.append(dawzxx.getLh());
                if (dawzxx.getMh() == 1 || dawzxx.equals(1)) addressSbf.append("L");
                else if (dawzxx.getMh() == 2 || dawzxx.equals(2l)) addressSbf.append("R");
                if (dawzxx.getJh() < 10) addressSbf.append("0").append(dawzxx.getJh());
                else addressSbf.append(dawzxx.getJh());
                if (dawzxx.getGh() < 10) addressSbf.append("0").append(dawzxx.getGh());
                else addressSbf.append(dawzxx.getGh());
log.info("动态PDA库房地址为:" + addressSbf.toString());
                try {
                    //Socket发送给PDA服务器代码
Socket socket = new Socket();//需要动态根据位置发送服务
SocketAddress socketAddress = new InetSocketAddress(hostIP, 1001);
socket.connect(socketAddress, 3000);//连接三秒钟超时设置
OutputStream outputStream = socket.getOutputStream();
StringBuffer sbf = new StringBuffer();
sbf.append("<?xml version='1.0' encoding='gb2312'?>");
sbf.append("<XMLPackage>");
sbf.append("<Command CmdType='2'/>");
sbf.append("<data>");
sbf.append("<row Code='" + tpaDast.getDacode() + "' Name='" + cqrxm + "' Address='" + addressSbf.toString() + "' Archives_id='" + tpaDast.getId() + "' State='" + type + "'/>"); //还档state变成2,其它都是一样
sbf.append("</data>");
sbf.append("</XMLPackage>");
log.info("发送" + tpaDast.getDacode() + "信息为:\n" + sbf.toString());
outputStream.write(sbf.toString().getBytes());
log.info("Socket主机端连接信息为:\n" + socket);
InputStream is = socket.getInputStream();
                    byte[] bytes = new byte[1024];
                    int n = is.read(bytes);
log.info(tpaDast.getDacode() + "发送给PDA系统,回调信息为:\n" + new String(bytes, 0, n));
outputStream.flush();
outputStream.close();
is.close();
} catch (Exception e) {
                    log.info("调档发送PDA服务信息错误,调档失败,原因是PDA服务器没有开启!具体信息如下:\n" + e.getMessage());
                    return false;
}
            }
        }
    }
    return true;
}

 

 

时至今日我又翻阅了相关资料系统的进行了学习,情况总结如下:

 

概念:

Socket是一组编程接口(API), 是对TCP/IP协议的封装和应用。介于传输层和应用层,大致驻留在 OSI 模型的会话层,向应用层提供统一的编程接口。应用层不必了解TCP/IP协议细节。直接通过对Socket接口函数的调用完成数据在IP网络的传输。

 

分类:

基于传输层差异,可以将Socket分为4种类型:
    (1)基于TCP的Socket:提供给应用层可靠的流式数据服务,使用TCP的Socket应用程序协议:BGP,HTTP,FTP,TELNET等。优点:基于数据传输的可靠性。
   (2)基于UDP的Socket:适用于数据传输可靠性要求不高的场合。基于UDP的Socket应用程序或协议有:RIP,SNMP,L2TP等。
  (3)基于RawIp的Socket:非连接,不可靠的数据传输。特点:能使应用程序直接访问网络层。基于RawIp的Socket有ping ,tracert,ospf等。
  (4)基于链路层的Socket。为IS-IS协议提供的Socket接口。使IS-IS协议可通过Socket直接访问链路层。非连接,不可靠通信服务。

 

实践:

我主要是针对socket实现方式TPC/ID和UPD的两种实现方式进行了学习,先来看看他们的通讯方式链接过程图(图片来源于网络):

TCP/IP链接过程



 UPD链接过程:



 对比两者区别:

TCP:Transimission Control Protocol传输控制协议。

UPD:User Datagram Protocol用户数据包协议。

两者都属于OSI模型中的第四层——传输层的协议。

两者相比:

TCP协议面向连接,UDP协议面向非连接;(链接)

TCP协议传输速度慢,UDP协议传输速度快;(速度)

TCP有丢包重传机制,UDP没有;(重传)

TCP协议保证数据正确性,UDP协议可能丢包;(正确性)

TCP适合传递大量数据,UPD适合传递少量数据。(数据量)

 

说了基本概念后,我用代码编写了主机、客户端进行socket通讯的代码,代码如下:

服务端代码socketServer.java类:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
 * Created by 峰 on 2017/4/6.
 * 服务器类
 */
public class socketServer {
    private int port = 8189;// 默认服务器端口
public socketServer() {
    }
    // 创建指定端口的服务器
public socketServer(int port) {
        this.port = port;
}

    // 提供服务
public void service() {
        try {// 建立服务器连接
ServerSocket server = new ServerSocket(port);
// 等待客户连接
Socket socket = server.accept();
            try {
                // 读取客户端传过来信息的DataInputStream
DataInputStream in = new DataInputStream(socket
                        .getInputStream());
// 向客户端发送信息的DataOutputStream
DataOutputStream out = new DataOutputStream(socket
                        .getOutputStream());
// 获取控制台输入的Scanner
Scanner scanner = new Scanner(System.in);
                while (true) {
                    // 读取来自客户端的信息
String accpet = in.readUTF();
System.out.println(accpet);
String send = scanner.nextLine();
System.out.println("服务器:" + send);
// 把服务器端的输入发给客户端
out.writeUTF("服务器:" + send);
}
            } finally {// 建立连接失败的话不会执行socket.close();
socket.close();
}
        } catch (IOException e) {
            e.printStackTrace();
}
    }

    public static void main(String[] args) {
        new socketServer().service();
}
}

 

客户端代码socketClient.java类:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
/**
 * Created by 峰 on 2017/4/9.
 * 客户端类
 */
public class socketClient {

    private String host = "localhost";// 默认连接到本机
private int port = 8189;// 默认连接到端口8189
public socketClient() {
    }

    // 连接到指定的主机和端口
public socketClient(String host, int port) {
        this.host = host;
        this.port = port;
}

    public void chat() {
        try {
            // 连接到服务器
Socket socket = new Socket(host, port);
            try {
                // 读取服务器端传过来信息的DataInputStream
DataInputStream in = new DataInputStream(socket
                        .getInputStream());
// 向服务器端发送信息的DataOutputStream
DataOutputStream out = new DataOutputStream(socket
                        .getOutputStream());
// 装饰标准输入流,用于从控制台输入
Scanner scanner = new Scanner(System.in);
                while (true) {
                    String send = scanner.nextLine();
System.out.println("客户端:" + send);
// 把从控制台得到的信息传送给服务器
out.writeUTF("客户端:" + send);
// 读取来自服务器的信息
String accpet = in.readUTF();
System.out.println(accpet);
}

            } finally {
                socket.close();
}
        } catch (IOException e) {
            e.printStackTrace();
}
    }

    public static void main(String[] args) {
        new socketClient().chat();
}

}

 

测试结果:

服务端信息截图:

 客户端信息截图:



 

 

通讯原理及过程图解(来源于网络):



 
 

 

附言:因为时间问题、我这里只研究了java.net下的socket,其实还有别的实现方式,比如linux下面也有socket,参考 http://blog.csdn.net/hguisu/article/details/7445768/

现在网络上也有很多很好的socket学习文章,具体可以参考下面链接(当然我也都是看过了的)

http://acm.tzc.edu.cn/acmhome/projectList.do?method=projectNewsDetail&nid=2

http://blog.csdn.net/hguisu/article/details/7445768/

http://www.cnblogs.com/kinghitomi/archive/2012/01/19/2327424.html

  • 大小: 40.2 KB
  • 大小: 27.7 KB
  • 大小: 82.4 KB
  • 大小: 13.6 KB
  • 大小: 13 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics