• 结合多线程实现socket
    • 使用非线程池(拓展Thread)
    • 使用线程池(Executor pool)
  • 使用DatagramPacket DatagramSocket开发UDP/IP程序
    • 使用UDP获取服务端时间
  • 其他
    • 使用socket类作为客户端链接网站:
    • 用ServerSocket创建一个web服务器:

首先:accept()和Read()方法都有阻塞特性

结合多线程实现socket

在Socket技术中,常用的实践方式就是Socket结合Thread多线程技术,客户端每发起一次新的请求,就把这个请求交给新创建的线程来执行这次业务。当然,如果使用线程池技术,则会更加高效。本示例先使用原始的非线程池来进行演示。

//socket类提供了两个方法用于得到输入流和输出流,分别是getInputStream()和getOutputStream() 可以对其进行包装
//例如:Socket socket = new Socket(“localhost”,8189);
// PrintStream oStream = new PrintStream( new BufferedOutputStream(socket.getOutputStream()));
//DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
一个使用DataInputStream的简单例子:

 public static void main(String [] args){String serverName = args[0];int port = Integer.parseInt(args[1]);try{System.out.println("连接到主机:" + serverName + " ,端口号:" + port);Socket client = new Socket(serverName, port);System.out.println("远程主机地址:" + client.getRemoteSocketAddress());OutputStream outToServer = client.getOutputStream();DataOutputStream out = new DataOutputStream(outToServer);out.writeUTF("Hello from " + client.getLocalSocketAddress());InputStream inFromServer = client.getInputStream();DataInputStream in = new DataInputStream(inFromServer);System.out.println("服务器响应: " + in.readUTF());client.close();}catch(IOException e){e.printStackTrace();}}

使用非线程池(拓展Thread)

beginthread:


//多线程实现socket
public class BeginThread extends Thread{private Socket socket;public BeginThread(Socket socket){super();this.socket = socket;}@Overridepublic void run(){try{InputStream inputStream = socket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream);char[] charArr = new char[1000];int readLen = -1;while((readLen = (inputStreamReader.read(charArr))) != -1){String newString = new String(charArr,0,readLen);System.out.println(newString);}inputStreamReader.close();inputStream.close();//关闭两个流socket.close();//关闭socket}catch (IOException e){e.printStackTrace();}}
}

beginserver类:


public class BeginServer {public static void main(String[]args) throws IOException {ServerSocket socket = new ServerSocket(8888);int runTag = 1;while (runTag == 1){Socket socket1 = socket.accept();BeginThread beginThread = new BeginThread(socket1);beginThread.start();}socket.close();}
}

BeginClient :


public class BeginClient {public static void main(String[]args) throws IOException {Socket socket = new Socket("localhost",8888);OutputStream outputStream = socket.getOutputStream();
//        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
//        outputStreamWriter.write(String.valueOf("我是中国人".getBytes(StandardCharsets.UTF_8)));outputStream.write("我是中国人yaoo".getBytes(StandardCharsets.UTF_8));outputStream.close();socket.close();}
}

客户端每次发完一条数据就会关闭连接,而服务端一直会有线程接收请求。修改客户端的字符串,服务端结果:

由于 Socket socket1 = socket.accept();的阻塞特性,只有服务端受到客户端的信号之后才会开启一个新的线程。

使用线程池(Executor pool)

将以上代码修改为使用线程池:
beginThread只需要修改为
implements Runnable
而beginServer改为:


public class BeginServer {private ServerSocket serverSocket;
private Executor pool;
public BeginServer(int port,int poolSize)
{try{serverSocket = new ServerSocket(port);pool = Executors.newFixedThreadPool(poolSize);}catch (IOException e){e.printStackTrace();}
}public void startServer() {try {while (true) {Socket socket = serverSocket.accept();pool.execute(new BeginThread(socket));}} catch (IOException e) {e.printStackTrace();}
}public static void main(String[]args) throws IOException {BeginServer beginServer = new BeginServer(8888,10000);beginServer.startServer();}
}


结果是一样的。

使用DatagramPacket DatagramSocket开发UDP/IP程序

DatagramPacket DatagramSocket是用来支持数据报通信的两个类,前者由于表示数据报,后者用于建立通信连接
写改程序首先需要建立一个DatagramSocket对象,用来接收或者发送数据报,然后以DatagramPacket 作为数据传输的载体。

使用UDP获取服务端时间

client:


public class UdpClient {public void go() throws IOException, UnknownHostException{DatagramPacket ingramPacket;DatagramPacket outgramPacket;DatagramSocket datagramSocket;InetAddress serverAdress;byte[]msg = new byte[100];//缓冲区String receivedmsg;datagramSocket = new DatagramSocket();System.out.println("an udpclient ,datagramsocket:"+datagramSocket.getPort()+"localport:"+datagramSocket.getLocalPort());serverAdress = InetAddress.getLocalHost();outgramPacket = new DatagramPacket(msg,1,serverAdress,8000);//send to port 8000datagramSocket.send(outgramPacket);//make the request to the serveringramPacket = new DatagramPacket(msg,msg.length);//set up a datagram packet to receive server's responsedatagramSocket.receive(ingramPacket);receivedmsg = new String(ingramPacket.getData(),0,ingramPacket.getLength());System.out.println(receivedmsg);//print the data received from the serverdatagramSocket.close();}public static void main(String[]args) throws IOException {UdpClient udpClient = new UdpClient();try {udpClient.go();}catch (Exception e){System.out.println(e);}}
}

server:


public class UdpServer {public byte[]getTime(){Date d = new Date();return d.toString().getBytes(StandardCharsets.UTF_8);
}
public void go() throws IOException{DatagramPacket inDataPacket;DatagramPacket outDataPacket;DatagramSocket datagramSocket;InetAddress clientAdress;int clientPort;byte[]msg = new byte[10];//Incoming data buffer.ignoredbyte[]time;datagramSocket = new DatagramSocket(8000);//allocate a socket to man port 8000 for requestsSystem.out.println("UDPserver :"+datagramSocket.getPort()+"local is:"+datagramSocket.getLocalPort());System.out.println("udpserver active on port 8000");while (true){inDataPacket = new DatagramPacket(msg,msg.length);datagramSocket.receive(inDataPacket);//get the messageclientAdress = inDataPacket.getAddress();clientPort = inDataPacket.getPort();time=getTime();outDataPacket = new DatagramPacket(time,time.length,clientAdress,clientPort);datagramSocket.send(outDataPacket);//send the packet}
}public static void main(String[]args){UdpServer udpServer = new UdpServer();try{udpServer.go();}catch (IOException e){e.printStackTrace();}}}

结果:


客户端接收一次数据之后即关闭连接,而服务端一直可以接收请求。

其他

使用socket类作为客户端链接网站:

public class Hzy {public static void main(String args[]) throws IOException {Socket socket = null;try {socket = new Socket("www.csdn.net", 80);System.out.println("socket连接成功");} catch (IOException e) {System.out.println("socket连接失败");e.printStackTrace();} finally {socket.close();}
}}


注意:如果host为不存在的域名,会发生报错

用ServerSocket创建一个web服务器:

public class Hzy {public static void main(String args[]) throws IOException {ServerSocket serverSocket = new ServerSocket(6666,1, InetAddress.getByName("127.0.0.1"));Socket socket = serverSocket.accept();InputStream inputStream = socket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String getString = "";while (!"".equals(getString = bufferedReader.readLine())) {System.out.println(getString);}OutputStream outputStream = socket.getOutputStream();outputStream.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());outputStream.write("<html><body><a href='http://www.baidu.com'>i am baidu.com welcome you!</a></body></html>".getBytes());outputStream.flush();inputStream.close();outputStream.close();socket.close();serverSocket.close();}}

这个代码不知道为什么打开浏览器还是没法访问,原因还未找到。

文件目录:

chartserver:


public class ChatServer {private static final int SOCKET_PORT = 52000;public static ArrayList<SocketBean> mSocketList = new ArrayList<SocketBean>();private void initServer() {try {// 创建一个ServerSocket,用于监听客户端Socket的连接请求ServerSocket server = new ServerSocket(SOCKET_PORT);while (true) {// 每当接收到客户端的Socket请求,服务器端也相应的创建一个SocketSocketBean socket = new SocketBean(DateUtil.getTimeId(), server.accept());mSocketList.add(socket);// 每连接一个客户端,启动一个ServerThread线程为该客户端服务new Thread(new ServerThread(socket)).start();}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {ChatServer server = new ChatServer();server.initServer();}
}

ServerThread


public class ServerThread implements Runnable {private SocketBean mSocket = null;private BufferedReader mReader = null;public ServerThread(SocketBean mSocket) throws IOException {this.mSocket = mSocket;mReader = new BufferedReader(new InputStreamReader(mSocket.socket.getInputStream()));}@Overridepublic void run() {try {String content = null;// 循环不断地从Socket中读取客户端发送过来的数据while ((content = mReader.readLine()) != null) {System.out.println("content="+content);int pos = content.indexOf("|");// 包头格式为:动作名称|设备编号|昵称|时间|对方设备编号String head = content.substring(0, pos);String body = content.substring(pos+1);String[] splitArray = head.split(",");String action = splitArray[0];System.out.println("action="+action);if (action.equals("LOGIN")) {login(splitArray[1], splitArray[2], splitArray[3]);} else if (action.equals("LOGOUT")) {logout(splitArray[1]);break;} else if (action.equals("SENDMSG")) {sendmsg("RECVMSG", splitArray[2], splitArray[4], splitArray[1], body);} else if (action.equals("GETLIST")) {getlist(splitArray[1]);} else if (action.equals("SENDPHOTO")) {sendmsg("RECVPHOTO", splitArray[2], splitArray[4], splitArray[1], body);} else if (action.equals("SENDSOUND")) {sendmsg("RECVSOUND", splitArray[2], splitArray[4], splitArray[1], body);}}} catch (Exception e) {e.printStackTrace();}}private void login(String deviceId, String nickName, String loginTime) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id)) {item.deviceId = deviceId;item.nickName = nickName;item.loginTime = loginTime;ChatServer.mSocketList.set(i, item);break;}}}private String getFriend() {String friends = "GETLIST,";for (SocketBean item : ChatServer.mSocketList) {if (item.deviceId!=null && item.deviceId.length()>0) {String friend = String.format("|%s,%s,%s", item.deviceId, item.nickName, item.loginTime);friends += friend;}}return friends;}private void getlist(String deviceId) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println(getFriend());break;}}}private void logout(String deviceId) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println("LOGOUT,|");item.socket.close();ChatServer.mSocketList.remove(i);break;}}}private void sendmsg(String respAction, String otherName, String otherId, String selfId, String message) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.deviceId.equals(otherId)) {String content = String.format("%s,%s,%s,%s|%s", respAction, selfId, otherName, DateUtil.getNowTime(), message);System.out.println("resp="+content);PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println(content);break;}}}}

socketbean:


public class SocketBean {public String id;public Socket socket;public String deviceId;public String nickName;public String loginTime;public SocketBean(String id, Socket socket) {this.id = id;this.socket = socket;this.deviceId = "";this.nickName = "";this.loginTime = "";}}

TestServer:


public class TestServer {private static final int SOCKET_PORT = 51000;private void initServer() {try {// 创建一个ServerSocket,用于监听客户端Socket的连接请求ServerSocket server = new ServerSocket(SOCKET_PORT);while (true) {Socket socket = server.accept();new Thread(new ServerThread(socket)).start();}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {TestServer server = new TestServer();server.initServer();}private class ServerThread implements Runnable {private Socket mSocket;private BufferedReader mReader;public ServerThread(Socket socket) throws IOException {mSocket = socket;mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));}@Overridepublic void run() {try {String content = null;// 循环不断地从Socket中读取客户端发送过来的数据while ((content = mReader.readLine()) != null) {System.out.println("收到客户端消息:"+content);PrintStream ps = new PrintStream(mSocket.getOutputStream());ps.println("hi,很高兴认识你");}} catch (Exception e) {e.printStackTrace();}}}}

客户端:


public class MessageTransmit implements Runnable {private static final String TAG = "MessageTransmit";// 以下为Socket服务器的ip和端口,根据实际情况修改private static final String SOCKET_IP = "192.168.0.212";private static final int SOCKET_PORT = 51000;private Socket mSocket;private BufferedReader mReader = null;private OutputStream mWriter = null;@Overridepublic void run() {mSocket = new Socket();try {mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));mWriter = mSocket.getOutputStream();// 启动一条子线程来读取服务器的返回数据new RecvThread().start();Looper.prepare();Looper.loop();} catch (Exception e) {e.printStackTrace();}}// 定义接收UI线程的Handler对象,App向后台服务器发送消息public Handler mRecvHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {Log.d(TAG, "handleMessage: "+msg.obj);// 换行符相当于回车键,表示我写好了发出去吧String send_msg = msg.obj.toString()+"\n";try {mWriter.write(send_msg.getBytes("utf8"));} catch (Exception e) {e.printStackTrace();}}};// 定义消息接收子线程,App从后台服务器接收消息private class RecvThread extends Thread {@Overridepublic void run() {try {String content = null;while ((content = mReader.readLine()) != null) {// 读取到来自服务器的数据Message msg = Message.obtain();msg.obj = content;SocketActivity.mHandler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}}}
public class ClientThread implements Runnable {private static final String TAG = "ClientThread";private static final String SOCKET_IP = "192.168.253.1";//private static final String SOCKET_IP = "192.168.0.212";private static final int SOCKET_PORT = 52000;public static final String REQUEST_URL = "http://192.168.253.1:8080/UploadTest";private Context mContext;private Socket mSocket;public Handler mRecvHandler;private BufferedReader mReader = null;private OutputStream mWriter = null;public static String ACTION_RECV_MSG = "com.example.network.RECV_MSG";public static String ACTION_GET_LIST = "com.example.network.GET_LIST";public static String CONTENT = "CONTENT";public static String SPLIT_LINE = "|";public static String SPLIT_ITEM = ",";public static String LOGIN = "LOGIN";public static String LOGOUT = "LOGOUT";public static String SENDMSG = "SENDMSG";public static String RECVMSG = "RECVMSG";public static String GETLIST = "GETLIST";public static String SENDPHOTO = "SENDPHOTO";public static String RECVPHOTO = "RECVPHOTO";public static String SENDSOUND = "SENDSOUND";public static String RECVSOUND = "RECVSOUND";public ClientThread(Context context) {mContext = context;}@Overridepublic void run() {Log.d(TAG, "run");mSocket = new Socket();try {Log.d(TAG, "connect");mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));Log.d(TAG, "getOutputStream");mWriter = mSocket.getOutputStream();Log.d(TAG, "RecvThread");// 启动一条子线程来读取服务器相应的数据new RecvThread().start();Looper.prepare();// 定义接收UI线程的Handler对象,App向后台服务器发送消息// 如果是在Application中启动线程,则mRecvHandler要在线程启动后才能初始化// 并且要在Looper.prepare之后执行初始化动作mRecvHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// 接收到UI线程的用户输入的数据try {mWriter.write(msg.obj.toString().getBytes("utf8"));} catch (Exception e) {e.printStackTrace();}}};Looper.loop();} catch (Exception e) {e.printStackTrace();notify(99, e.getMessage());}}// 定义消息接收子线程,App从后台服务器接收消息private class RecvThread extends Thread {@Overridepublic void run() {String content = null;try {while ((content = mReader.readLine()) != null) {// 读取到来自服务器的数据之后,发送消息通知ClientThread.this.notify(0, content);}} catch (Exception e) {e.printStackTrace();ClientThread.this.notify(97, e.getMessage());}}}private void notify(int type, String message) {if (type == 99) {String content = String.format("%s%s%s%s", "ERROR", SPLIT_ITEM, SPLIT_LINE, message);Intent intent1 = new Intent(ACTION_RECV_MSG);intent1.putExtra(CONTENT, content);mContext.sendBroadcast(intent1);Intent intent2 = new Intent(ACTION_GET_LIST);intent2.putExtra(CONTENT, content);mContext.sendBroadcast(intent2);} else {int pos = message.indexOf(SPLIT_LINE);String head = message.substring(0, pos - 1);String[] splitArray = head.split(SPLIT_ITEM);String action = "";if (splitArray[0].equals(RECVMSG) || splitArray[0].equals(RECVPHOTO) || splitArray[0].equals(RECVSOUND)) {action = ACTION_RECV_MSG;} else if (splitArray[0].equals(GETLIST)) {action = ACTION_GET_LIST;}Log.d(TAG, "action=" + action + ", message=" + message);Intent intent = new Intent(action);intent.putExtra(CONTENT, message);mContext.sendBroadcast(intent);}}}

【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序相关推荐

  1. Java基于socket编程实现局域网内简单通信

    运行客户端程序将创建一个客户端套接字,并与指定的服务器建立连接,接收了服务端发来的消息后关闭连接.服务端启动后会循环接收客户端连接,在接收到连接后,向该客户端发送 "Hello World! ...

  2. java中socket编程实例_Java中socket编程的实现过程(代码实例)

    本篇文章给大家带来的内容是关于socket编程的实现过程,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.socket 服务器搭建 实例化socket服务器,循环获取请求packa ...

  3. java使用socket实现一个多线程web服务器

    全栈工程师开发手册 (作者:栾鹏) java教程全解 java使用socket实现一个多线程web服务器 除了服务器类,还包括请求类和响应类 请求类:获取客户的HTTP请求,分析客户所需要的文件 响应 ...

  4. Python3进阶--Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

    第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...

  5. api有哪些 javasocket_基于java的socket编程及API解析

    一.socket通讯过程 1.socket与socket编程简介: socket 被翻译为"套接字",它是计算机之间进行通信的一种约定或一种方式.通过 socket 这种约定,一台 ...

  6. Java多线程:线程安全和非线程安全的集合对象

    转载自  Java多线程:线程安全和非线程安全的集合对象 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到 ...

  7. JAVA中的线程安全与非线程安全

    ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题.面对这样 ...

  8. JAVA中的线程安全与非线程安全,java面试题,java高级笔试题

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 转自 ...

  9. Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)

    转自:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html 一.概述 关于Socket编程的基本方法在基础篇里已经讲过,今天把它给 ...

最新文章

  1. lucene索引文件大小优化小结
  2. 【转】Ubuntu VI基本用法
  3. xp系统 javafx_使用JavaFX构建React系统
  4. 通达信公式-涨幅限制
  5. corrplot包与ggcorrplot相关图(二)
  6. mysql foxpro_|DBSync for FoxPro and MySQL(数据库同步工具)下载v4.7.1免费版 - 欧普软件下载...
  7. python微信语音转发方法_微信怎么转发语音(想要转到别的群或者人这样做)
  8. ACE admin 后台管理框架
  9. 解决du df结果不一样的问题
  10. 室友还不知道FAST中国天眼是什么,快把这篇文章推给他,浅学一手卫星通信
  11. phonegap app推送新手教程与坑
  12. 7-3 IP地址转换分数 20
  13. cuda10.1安装
  14. 冯 . 诺依曼体系结构对计算机发展的限制
  15. 【Mysql数据库应用】
  16. 如何查看自己亚马逊的的库存容量?
  17. iOS Swift JSON转JSONString字符串
  18. 4.6 Cache Write Policy
  19. 如何得知深睡眠等各类进程的函数堆栈 -- DW-SW等
  20. python全栈学习总结二:数字、字符串、列表、元组、字典重要特点及方法

热门文章

  1. flink physical partition
  2. 浏览器卡怎么办_SD卡无法格式化怎么修复?简单修复方法介绍
  3. CSS box-shadow 盒子阴影属性
  4. python 重载id函数_Python函数重载实例
  5. 六十五、下一个更大的数系列,单调栈解决方法
  6. 八十、 Springboot整合异步任务和定时任务
  7. 小程序bindtap参数传递
  8. Vue 学习第八天
  9. NLP领域最近比较火的Prompt,能否借鉴到多模态领域?一文跟进最新进展
  10. 吊打一切现有开源OCR项目!90% +准确率,训练部署一条龙