java TCP/IP Socket编程例子

 

前一段时间刚做了个java程序和网络上多台机器的c程序通讯的项目,遵循的是TCP/IP协议,用到了java的Socket编程。网络通讯是java的强项,用TCP/IP协议可以方便的和网络上的其他程序互通消息。

先来介绍下网络协议:
    TCP/IP
        Transmission Control Protocol 传输控制协议
        Internet Protocol 互联网协议
    UDP
        User Datagram Protocol 用户数据协议

连接协议:
    分为:
    面向连接协议: Connection Oriented Protocol
    非连接协议: Connectionless Protocol

    1).面向连接协议是指两台电脑在传输数据前,先会建立一个专属的连接。就如电信局的交换机会为打电话双方提供专属连接一样。
    Internet上的面向连接协议就是TCP/IP
    特点:确认回应;分组序号;流量控制。
    TCP/IP属于可靠性传输,适合不容许有传输错误的网络程序设计使用

    2).非连接协议:无专属连接,无分组,容错,距离短,可同时对多台电脑进行数据传输
    Internet上的非连接协议就是UDP

    TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。


Socket 是程序与网络间的一种接口,大部分网络应用程序都是点对点的,所谓点就是服务器端和客户端所执行的程序。Socket是用来接收和传送分组的一个端点。

java的Socket编程要用到java.net包,最常用的是net包下的6个类:InetAddress(互联网协议 (IP) 地址)类,Socket(套接字)类,ServerSocket(套接字服务器)类,DatagramSocket(发送和接收数据报包的套接字)类,DatagramPacket(数据报包)类,MulticastSocket(多播数据报套接字类用于发送和接收 IP 多播包)类,其中InetAddress、Socket、ServerSocket类是属于TCP面向连接协议,DatagramSocket、DatagramPacket和MulticastSocket类则属于UDP非连接协议的传送类。

本项目因为使用TCP/IP协议,主要用到Socket和ServerSocket类

项目代码如下


Java代码  01.package com.sse.monitor.serv; 
02. 
03.import java.io.DataInputStream; 
04.import java.io.IOException; 
05.import java.io.InputStream; 
06.import java.io.OutputStream; 
07.import java.io.BufferedOutputStream; 
08. 
09.import java.net.Socket; 
10.import java.net.UnknownHostException; 
11.import java.util.ArrayList; 
12. 
13.import com.sse.monitor.bean.Message; 
14.import com.sse.monitor.bean.MessageHead; 
15.import com.sse.monitor.bean.ResponseMessage; 
16.import com.sse.monitor.form.ListenerInvoke; 
17.import com.sse.monitor.form.MainForm; 
18.import com.sse.monitor.util.SwingUtils; 
19. 
20./**
21. * Socket套接字工厂,对外接口是静态方法 SocketFactory.request(String, String, String, int) 
22. * Copyright: Copyright (c) 2008 
23. * Company: conserv
24. * @author cuishen
25. * @version 1.3
26. */ 
27.public class SocketFactory { 
28.    private Socket socket = null; 
29.    private String targetIpAddress = null; 
30.    private int targetPort = 0; 
31.    private static SocketFactory sf = new SocketFactory(); 
32. 
33.    public SocketFactory() { 
34.    } 
35. 
36.    /**
37.     * 建立一条TCP/IP连接
38.     * @param targetIpAddress String 目标ip地址
39.     * @param targetPort String 目标端口
40.     * @throws IOException
41.     */ 
42.    private void connect(String targetIpAddress, int targetPort) throws IOException { 
43.        setTargetIpAddress(targetIpAddress); 
44.        setTargetPort(targetPort); 
45.        if(socket == null) 
46.            socket = new Socket(targetIpAddress, targetPort); 
47.    } 
48. 
49.    /**
50.     * 这是对外接口。发送命令,接收反馈和接收message放两个线程,
51.     * 发送命令并接收反馈是短连接,所以每次执行成功后,将销毁socket并终止线程,
52.     * 接收message是长连接,所以可能会new出n个线程,建议对接收message的线程做缓存
53.     * @param commandType String 命令类型
54.     * @param commandContent String 命令内容
55.     * @param targetIP String 目标ip
56.     * @param targetPort int 目标端口
57.     */ 
58.    public static void request(String commandType, String commandContent, String targetIP, int targetPort) { 
59.        if (commandType.equalsIgnoreCase(MessageFactory.SCAN_COMMAND)) { 
60.            sf.new GetMessageSocketThread(commandType, commandContent, targetIP, targetPort); 
61.        } else { 
62.            sf.new RequestSocketThread(commandType, commandContent, targetIP, targetPort); 
63.        } 
64.    } 
65. 
66.    /**
67.     * 发送请求
68.     * @param commandType String 命令类型
69.     * @param commandContent String 命令内容
70.     * @param targetIp String 目标ip
71.     */ 
72.    private void sendRequest(String commandType, String commandContent, String targetIp) { 
73.        OutputStream os = null; 
74.        BufferedOutputStream bs = null; 
75.        try { 
76.            os = socket.getOutputStream(); 
77.            bs = new BufferedOutputStream(os); 
78.            char[] message = MessageFactory.makeRequestMessage(targetIp, commandType, commandContent, MessageFactory.COMMAND_TRADE_CODE, MessageFactory.RIGHT_COMMAND, MessageFactory.MESSAGE_END_FLAG); 
79.            for (int i = 0; i < message.length; i++) 
80.                bs.write(new String(message).getBytes(), i, 1); 
81.            bs.flush(); 
82.            SwingUtils.appendLog(MainForm.jTextArea, "发送请求:'" + commandType + "' '" + commandContent + "' '" + targetIp + "'", ReadConfig.commandStateShowLineCount); 
83.        } catch (IOException e) { 
84.            SwingUtils.appendLog(MainForm.jTextArea, "Error!!! 发送请求:'" + commandType + "' '" + commandContent + "' '" + targetIp + "'失败!! " + e.getMessage(), ReadConfig.commandStateShowLineCount); 
85.            e.printStackTrace(); 
86.        } catch (Exception e) { 
87.            e.printStackTrace(); 
88.        } finally { 
89.        } 
90.    } 
91. 
92.    /**
93.     * 获得反馈
94.     * 
95.     * @return 如果成功获得反馈,则返回true;否则返回false
96.     */ 
97.    private boolean getResponse() { 
98.        InputStream is = null; 
99.        DataInputStream di = null; 
100.        boolean returnFlag = false; 
101.        try { 
102.            is = socket.getInputStream(); 
103.            di = new DataInputStream(is); 
104.            byte[] temp = new byte[1]; 
105.            int flag = 0; 
106.            ArrayList tempByteList = new ArrayList(); 
107.            int i = 0; 
108.            while (flag != -1) { 
109.                i++; 
110.                flag = di.read(temp = new byte[1]); 
111.                if (flag != -1) 
112.                    tempByteList.add(temp); 
113.                if (i == 38) 
114.                    break; 
115.            } 
116.            if (i == 1) { 
117.                SwingUtils.Error("未收到response!!!"); 
118.                return false; 
119.            } 
120.            MessageHead messageHead = MessageFactory.readHead(tempByteList); 
121. 
122.            SwingUtils.appendLog(MainForm.jTextArea, "收到 response", ReadConfig.commandStateShowLineCount); 
123. 
124.            tempByteList = new ArrayList(); 
125.            i = 0; 
126.            while (flag != -1) { 
127.                i++; 
128.                flag = di.read(temp = new byte[1]); 
129.                if (flag != -1) 
130.                    tempByteList.add(temp); 
131.                if (i == 26) 
132.                    break; 
133.            } 
134.            byte[] length = new byte[4]; 
135.            di.read(length); 
136.            int len = Integer.parseInt(new String(length, MessageFactory.DEFAULT_CHAR_SET).trim()); 
137.            flag = 0; 
138.            for (int j = 0; j < (len + 37); j++) { 
139.                flag = di.read(temp = new byte[1]); 
140.                if (flag == -1) 
141.                    break; 
142.                tempByteList.add(temp); 
143.            } 
144. 
145.            ResponseMessage rm = MessageFactory.readResponseMessage(tempByteList, len); 
146. 
147.            if (messageHead.getErrorCode().equals(MessageFactory.SUCCESS)) 
148.                returnFlag = true; 
149.            else 
150.                SwingUtils.Error("errorCode: " + messageHead.getErrorCode() + "; content: " + rm.getCommandContent()); 
151.        } catch (IOException e) { 
152.            e.printStackTrace(); 
153.        } finally { 
154.        } 
155.        return returnFlag; 
156.    } 
157. 
158.    /**
159.     * 分发消息的方法,将消息按进程名发送到对应的消息缓存 
160.     *
161.     * 消息缓存ListenerInvoke.messageMap,key = machineName +
162.     * '|' + programName + '|' + processId, value = messageList
163.     * 存放messageMap里面的键名的List -- ListenerInvoke.messageMapKeyList
164.     * 进程状态缓存ListenerInvoke.processStateMap, key = machineName + '|' +
165.     * programName + '|' + processId, value = String
166.     * 
167.     * @param message Message
168.     */ 
169.    private void distributeMess(Message message) { 
170.        String machineName = message.getMachineName(); 
171.        String programName = message.getProgramName(); 
172.        String processId = message.getProcessId(); 
173.        String content = message.getContent(); 
174.        String key = machineName + '|' + programName + '|' + processId; 
175.        key = key.trim(); 
176.        ArrayList messageList = null; 
177.        if (ListenerInvoke.messageMap.get(key) == null) { 
178.            synchronized (ListenerInvoke.messageMap) { 
179.                if (ListenerInvoke.messageMap.get(key) == null) { 
180.                    messageList = new ArrayList(); 
181.                    messageList.add(content);            
182.                    ListenerInvoke.messageMap.put(key, messageList); 
183.                } 
184.            } 
185.        } else { 
186.            messageList = (ArrayList) ListenerInvoke.messageMap.get(key); 
187.            synchronized (messageList) { 
188.                if (ListenerInvoke.messageMap.get(key) != null) { 
189.                    messageList.add(content); 
190.                    if (!ReadConfig.threadDeleteMessCacheOrFIFO 
191.                            && messageList.size() >= ReadConfig.messageCacheSizeLimit) 
192.                        messageList.remove(0); 
193.                } 
194.            } 
195.        } 
196.        if (!ListenerInvoke.messageMapKeyList.contains(key)) { 
197.            synchronized (ListenerInvoke.messageMapKeyList) { 
198.                if (!ListenerInvoke.messageMapKeyList.contains(key)) 
199.                    ListenerInvoke.messageMapKeyList.add(key); 
200.            } 
201.        } 
202.    } 
203. 
204.    /**
205.     * 接收message
206.     * @return Message
207.     */ 
208.    private boolean getMessage() { 
209.        InputStream is = null; 
210.        DataInputStream di = null; 
211.        Message message = null; 
212.        try { 
213.            if (this.socket == null)  return false; 
214.            is = this.socket.getInputStream(); 
215.            if (is == null)  return false; 
216.            di = new DataInputStream(is); 
217.            byte[] temp = new byte[1]; 
218.            int flag = 0; 
219.            ArrayList tempByteList = new ArrayList(); 
220.            int i = 0; 
221.            while (flag != -1) { 
222.                i++; 
223.                flag = di.read(temp = new byte[1]); 
224.                if (flag != -1) 
225.                    tempByteList.add(temp); 
226.                if (i == 38) 
227.                    break; 
228.            } 
229.            if (i == 1)  return false; 
230. 
231.            tempByteList = new ArrayList(); 
232.            i = 0; 
233.            while (flag != -1) { 
234.                i++; 
235.                flag = di.read(temp = new byte[1]); 
236.                if (flag != -1) 
237.                    tempByteList.add(temp); 
238.                if (i == 74) 
239.                    break; 
240.            } 
241.            byte[] length = new byte[4]; 
242.            di.read(length); 
243.            int len = Integer.parseInt(new String(length, 
244.                    MessageFactory.DEFAULT_CHAR_SET).trim()); 
245.            flag = 0; 
246.            for (int j = 0; j < len; j++) { 
247.                flag = di.read(temp = new byte[1]); 
248.                if (flag == -1) 
249.                    break; 
250.                tempByteList.add(temp); 
251.            } 
252.            message = MessageFactory.readMessage(tempByteList, len); 
253.            SwingUtils.appendLog(MainForm.jTextArea, "收到新 Message", 
254.                    ReadConfig.commandStateShowLineCount); 
255.            distributeMess(message);// 分发message 
256.        } catch (IOException e) { 
257.            e.printStackTrace(); 
258.        } finally { 
259.        } 
260.        return true; 
261.    } 
262. 
263.    /**
264.     * 负责发送请求接收反馈的内部线程类,每new一个RequestSocketThread线程,
265.     * 就new一个socket,建立一条专属连接,成功接收反馈后将销毁socket,终止线程。
266.     * 将发送请求,接收反馈放进内部线程处理,是为了防止套接字阻塞造成主线程挂死。
267.     * @author cuishen
268.     * @version 1.2
269.     */ 
270.    class RequestSocketThread implements Runnable { 
271.        private SocketFactory socketFactory; 
272.        private String commandType = null; 
273.        private String commandContent = null; 
274.        private String targetIP = null; 
275.        Thread t; 
276. 
277.        public RequestSocketThread(String commandType, String commandContent, String targetIP, int targetPort) { 
278.            this.socketFactory = new SocketFactory(); 
279.            try { 
280.                this.socketFactory.connect(ReadConfig.targetIpAddress, ReadConfig.targetPort); 
281.            } catch (UnknownHostException e) { 
282.                SwingUtils.Error("主机 IP 地址无法确定,无法建立连接! targetIP=" + ReadConfig.targetIpAddress + ", targetPort=" + ReadConfig.targetPort); 
283.                e.printStackTrace(); 
284.            } catch (IOException e) { 
285.                SwingUtils.Error("访问被拒绝,无法建立连接,请检查网络! targetIP=" + ReadConfig.targetIpAddress + ", targetPort=" + ReadConfig.targetPort); 
286.                e.printStackTrace(); 
287.            } 
288.            this.commandType = commandType; 
289.            this.commandContent = commandContent; 
290.            this.targetIP = targetIP; 
291.            t = new Thread(this); 
292.            t.start(); 
293.        } 
294. 
295.        public void run() { 
296.            this.socketFactory.sendRequest(commandType, commandContent, targetIP); 
297.            this.socketFactory.getResponse(); 
298.            stopThread(); 
299.        } 
300. 
301.        public void stopThread() { 
302.            try { 
303.                this.commandType = null; 
304.                this.commandContent = null; 
305.                this.targetIP = null; 
306.                socketFactory.closeSocket(); 
307.                socketFactory = null; 
308.                this.t.join(100); 
309.            } catch (InterruptedException e) { 
310.                e.printStackTrace(); 
311.            } finally { 
312.                t = null; 
313.            } 
314.        } 
315.    } 
316. 
317.    /**
318.     * 负责接收message的内部线程类,每new一个GetMessageSocketThread线程,
319.     * 就new一个socket,建立一条专属TCP/IP连接,getMessage是长连接,所以建议
320.     * 将该线程放入缓存方便管理
321.     * @author cuishen
322.     * @version 1.2
323.     */ 
324.    class GetMessageSocketThread implements Runnable { 
325.        private SocketFactory socketFactory; 
326.        private String commandType = null; 
327.        private String commandContent = null; 
328.        private String targetIP = null; 
329.        Thread t; 
330.        private boolean flag = false; 
331.        private boolean ifGetResponse = true; 
332.        private boolean ifGetMessage = true; 
333.        private boolean ifSendRequest = true; 
334.        private boolean ifCycle = true; 
335. 
336.        public GetMessageSocketThread(String commandType, String commandContent, String targetIP, int targetPort) { 
337.             
338.            this.socketFactory = new SocketFactory(); 
339.            try { 
340.                this.socketFactory.connect(ReadConfig.targetIpAddress, ReadConfig.targetPort); 
341.            } catch (UnknownHostException e) { 
342.                SwingUtils.Error("主机 IP 地址无法确定,无法建立连接! targetIP=" 
343.                        + ReadConfig.targetIpAddress + ", targetPort=" 
344.                        + ReadConfig.targetPort); 
345.                e.printStackTrace(); 
346.            } catch (IOException e) { 
347.                SwingUtils.Error("访问被拒绝,无法建立连接,请检查网络! targetIP=" 
348.                        + ReadConfig.targetIpAddress + ", targetPort=" 
349.                        + ReadConfig.targetPort); 
350.                e.printStackTrace(); 
351.            } 
352.            this.commandType = commandType; 
353.            this.commandContent = commandContent; 
354.            this.targetIP = targetIP; 
355.            t = new Thread(this); 
356.            t.start(); 
357.        } 
358. 
359.        public void run() { 
360.            while (ifCycle) { 
361.                if (ifSendRequest) { 
362.                    this.socketFactory.sendRequest(commandType, commandContent, targetIP); 
363.                    ifSendRequest = false; 
364.                } 
365.                if (ifGetResponse) { 
366.                    flag = socketFactory.getResponse(); 
367.                    ifGetResponse = false; 
368.                } 
369.                if (flag && ifGetMessage && socketFactory.socket != null) { 
370.                    if (!socketFactory.getMessage()) { 
371.                        try { 
372.                            Thread.sleep(ReadConfig.getMessageThreadSleep); 
373.                        } catch (InterruptedException e) { 
374.                            e.printStackTrace(); 
375.                        } 
376.                    } 
377.                } 
378.            } 
379.        } 
380. 
381.        public void stopThread() { 
382.            try { 
383.                this.commandType = null; 
384.                this.commandContent = null; 
385.                this.targetIP = null; 
386.                ifGetMessage = false; 
387.                ifCycle = false; 
388.                socketFactory.closeSocket(); 
389.                socketFactory = null; 
390.                this.t.join(100); 
391.            } catch (InterruptedException e) { 
392.                e.printStackTrace(); 
393.            } finally { 
394.                t = null; 
395.            } 
396.        } 
397.    } 
398. 
399.    /**
400.     * 关闭套接字
401.     */ 
402.    private void closeSocket() { 
403.        try { 
404.            if (!socket.isClosed()) 
405.                socket.close(); 
406.            socket = null; 
407.        } catch (IOException e) { 
408.            e.printStackTrace(); 
409.        } 
410.    } 
411. 
412.    /**
413.     * @return the targetIpAddress
414.     */ 
415.    public String getTargetIpAddress() { 
416.        return targetIpAddress; 
417.    } 
418. 
419.    /**
420.     * @param targetIpAddress
421.     *            the targetIpAddress to set
422.     */ 
423.    public void setTargetIpAddress(String targetIpAddress) { 
424.        this.targetIpAddress = targetIpAddress; 
425.    } 
426. 
427.    /**
428.     * @return the targetPort
429.     */ 
430.    public int getTargetPort() { 
431.        return targetPort; 
432.    } 
433. 
434.    /**
435.     * @param targetPort
436.     *            the targetPort to set
437.     */ 
438.    public void setTargetPort(int targetPort) { 
439.        this.targetPort = targetPort; 
440.    } 
441. 
442.} 


以上是Socket编程,ServerSocket在项目里没有用到,但是我也写了个包装类供参考

Java代码  01.package com.sse.monitor.serv; 
02. 
03.import java.io.IOException; 
04.import java.net.ServerSocket; 
05.import java.net.Socket; 
06. 
07./**
08. * 服务器套接字工厂
09. * Copyright: Copyright (c) 2008
10. * @author cuishen
11. * @version 1.0
12. */ 
13.public class ServerSocketFactory { 
14.    private static ServerSocket server; 
15.    private static Socket client; 
16.    private boolean ifRunServer = true; 
17.     
18.    public void runServer(int port) throws IOException { 
19.        //本地建立一个套接字服务器,等待其他机器访问 
20.        server = new ServerSocket(port); 
21.        System.out.println("Socket Server Start..."); 
22.        new ServerThread(); 
23.    } 
24.     
25. 
26.    class ServerThread implements Runnable { 
27.        Thread t; 
28.         
29.        public ServerThread() { 
30.            t = new Thread(this); 
31.            t.start(); 
32.        } 
33. 
34.        public void run() { 
35.            try { 
36.                while(ifRunServer) { 
37.                    if(client == null) client = server.accept(); 
38.                    if(client != null) //getMessage(); 
39.                    Thread.sleep(ReadConfig.serverThreadSleep); 
40.                } 
41.            } catch (InterruptedException e) { 
42.                e.printStackTrace(); 
43.            }  
44.            catch (IOException e) { 
45.                e.printStackTrace(); 
46.            } 
47.        } 
48.        public void stopThread() { 
49.            try { 
50.                ifRunServer = false; 
51.                this.t.join(100); 
52.            } catch (InterruptedException ex) { 
53.                System.out.println("socket服务器线程终止异常!!!"); 
54.            } finally { 
55.                t = null; 
56.            } 
57.        } 
58.    } 
59.} 


Socket编程就是运用Socket或者ServerSocket类搭配线程来使用(由于TCP/IP属于可靠性传输,不会丢包)。可能会因为在发送请求或者接受消息时Socket阻塞而导致主线程挂死,因此发送请求、接收消息的方法要放进子线程里处理;对于同一目标ip和端口,在同一个子线程里只能new一个Socket,也就是说,要对同一地址建立多条连接,就要开启多个线程。而且注意连接可能会因作用不同分长连接和短连接,要分别处理,本项目中发送请求和接受message就分别属于短连接和长连接,因此分别开发了RequestSocketThread和GetMessageSocketThread两个子线程区分对待。可以同时开发个Message类来封装打包和解包消息的方法(项目中开发MessageFactory.java),方便调用

【转自】hehffyy  http://www.360doc.com/userhome.aspx?userid=1332348&cid=40
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值