【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序
- 结合多线程实现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("i am baidu.com welcome you!".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);}}}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
