Java网络编程之TCP

Java网络编程之TCP

TCP主要需要两个类:Socket和ServerSocket,Socket是客户端连接服务器时创建,参数需要指定服务器的ip和端口,ServerSocket是服务器端创建,参数指定端口,如下:

Socket socket = new Socket("localhost",8888);//Client.java客户端
ServerSocket serverSocket = new ServerSocket(8888);//Server.java服务器端
//服务器ip为本机,端口为8888

我的想法:要实现单聊和群聊,首先,我得为标识每个客户端,我选择姓名,这样每个用户都知道是谁发的消息,那么,我需要每个姓名对应一个客户端Socket,用map存储

废话不多说,直接上代码:


  1. 客户端:

    public class TcpClient {
    
    	public static void main(String[] args) throws Exception {
    		Scanner scanner = new Scanner(System.in);
    		System.out.print("请输入用户名》》");
    		String userName = scanner.next();
    		Socket socket = new Socket("localhost",8888);
    		DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    		out.writeUTF(userName);
    		new Thread(new SendMsg(socket)).start();
    		new Thread(new ReceiveMsg(socket)).start();
    	}
    }
    
  2. 客户端发送消息线程:

    public class SendMsg implements Runnable{
    
    	private Socket socket;
    	public SendMsg(Socket socket) {
    		this.socket = socket;
    	}
    	@Override
    	public void run() {
    		try {
    			while(true) {
    				BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
    				String[] msg = buffer.readLine().split("@");
    				MessageBean messageBean = new MessageBean(msg[0],msg[1]);
    //				DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    //				out.writeUTF(msg);
    				ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    				out.writeObject(messageBean);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  3. 客户端接收消息线程:

    public class ReceiveMsg implements Runnable{
    	private Socket socket;
    	public ReceiveMsg(Socket socket) {
    		this.socket = socket;
    	}
    	@Override
    	public void run() {
    		try {
    			while(true) {
    				DataInputStream in = new DataInputStream(socket.getInputStream());
    				System.out.println(in.readUTF());
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  4. 服务器端:

    public class TcpServer {
    
    	public static void main(String[] args) throws Exception {
    		try {
    			//List<Socket> sockets = new ArrayList<>();
    			Map<String,Socket> map = new HashMap<>();
    			ServerSocket serverSocket = new ServerSocket(8888);
    			while(true) {
    				Socket socket = serverSocket.accept();
    				//服务器第一次接收到的信息一定是用户名
    				DataInputStream in = new DataInputStream(socket.getInputStream());
    				String username = in.readUTF();
    				synchronized (map) {
    					map.put(username, socket);
    				}
    				//能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果
    //				synchronized (sockets) {
    //					sockets.add(socket);
    //				}
    				new Thread(new ServerHandler(socket,map)).start();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  5. 服务器处理事务线程端:

    public class ServerHandler implements Runnable {
    
    	private Socket socket;
    	private Map<String, Socket> map;
    	public ServerHandler(Socket socket,Map<String, Socket> map) {
    		this.socket = socket;
    		this.map = map;
    	}
    	
    	public String findKey(Map<String, Socket> map,Socket socket) {
    		Iterator<String> it = map.keySet().iterator();
    		while (it.hasNext()) {
    			String key = it.next();
    			if (map.get(key).equals(socket)) return key;
    		 }
    		return null;
    	}
    	@Override
    	public void run() {
    		InetAddress address = socket.getInetAddress();
    		String ip = address.getHostAddress();
    		String username = findKey(map, socket);
    	    System.out.println("ip为"+ip+"的"+username+":上线了----");
    		try {
    			while(true) {
    				ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
    				MessageBean messageBean = (MessageBean) in.readObject();
    				String msg = messageBean.getMsg();
    				String toPerson = messageBean.getToPerson();
    				if ("all".equals(toPerson)) {
    					//群聊
    					msg = username+":"+msg;
    					for(String key : map.keySet()){
    					    if (username.equals(key)) {
    							continue;
    						}
    					    DataOutputStream out = new DataOutputStream(map.get(key).getOutputStream());
    					    out.writeUTF(msg);
    					}
    				}else {
    					//私聊
    					if (map.get(toPerson) == null) {
    						DataOutputStream out = new DataOutputStream(map.get(username).getOutputStream());
    					    out.writeUTF("抱歉,"+toPerson+"不在线。。。。");
    					}else {
    						msg = username+"对您私聊说:"+msg;
    						DataOutputStream out = new DataOutputStream(map.get(toPerson).getOutputStream());
    					    out.writeUTF(msg);
    					}
    				}
    			}
    		} catch (Exception e) {
    			//e.printStackTrace();
    			System.out.println(username+"下线了。。。。。");
    			synchronized (map) {
    				map.remove(username, socket);
    			}
    		}
    	}
    }
    
  6. 消息体类:

public class MessageBean implements Serializable{

	private String msg;
	private String toPerson;
	public MessageBean() {
		
	}
	public MessageBean(String msg,String toPerson) {
		this.msg = msg;
		this.toPerson = toPerson;
	}
	public String getMsg() {
		return msg;
	}
	public String getToPerson() {
		return toPerson;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public void setToPerson(String toPerson) {
		this.toPerson = toPerson;
	}
}

tcp私聊
tcp群聊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值