客户端

package chat;import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;// 客户端读取服务器端信息的线程
class ClientReadServer implements Runnable{private Socket socket;public ClientReadServer(Socket socket){this.socket=socket;}@Overridepublic void run() {// 获取服务器端输入流try {Scanner scanner=new Scanner(socket.getInputStream());System.out.println("test");while(scanner.hasNext()){// System.out.println("内容:"+scanner.nextLine());String meg=scanner.nextLine();System.out.println("服务端返回:"+meg);Frame.back(meg);}} catch (IOException e) {e.printStackTrace();}}
}// 客户端向服务器端发送信息的线程
class ClientSendServer implements Runnable{private static boolean sendFlag = false; //发送标记 点击发送后变trueprivate static String msg;private Socket socket;public ClientSendServer(Socket socket){this.socket=socket;}@Overridepublic void run() {try {// 获取服务器端的输出流PrintStream printStream=new PrintStream(socket.getOutputStream());while(true){if(sendFlag){printStream.println(msg);System.out.println("线程中run 发送:"+msg);sendFlag = false; //发送完成后置为false}//暂停进程 try {Thread.sleep(1000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}// System.out.println("进程进行中!");}} catch (IOException e) {e.printStackTrace();}}public static void change(String m,boolean b) {msg = m;sendFlag = true;}
}
public class Client {public  void mainClient () throws IOException{//1.客户端连接服务器端,返回套接字Socket对象Socket socket=new Socket("127.0.0.1",9527);//2.创建读取信息的线程和发送信息的线程Thread read=new Thread(new ClientReadServer(socket));Thread send=new Thread(new ClientSendServer(socket));//3.启动线程read.start();send.start();}public void send(String mes) {//发送信息System.out.println("准备发送的数据:"+mes);ClientSendServer.change(mes, true);}
}

用户界面

package chat;import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;import javax.swing.*;public class Frame extends JFrame {private static Client client;private static String backMeg = ""; //服务器返回消息private static JTextArea area;private static final long serialVersionUID = 1L;public static void back(String m) {backMeg = m;if(backMeg.contains(":")) {String context = backMeg;String name ="\n"+ backMeg.split("@")[1].split("\\:")[0] + ":";context=context.replace('@','\n'); //时间隔开context=context.replace("$",name);area.append(context+"\n"); //显示文本内容增加}}public Frame() {//JFrame frame = new JFrame("Chat2die"); //创建窗体对象setTitle("ChatRoom"); //标题setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(200, 200, 650, 600);  //位置 长宽setResizable(false); //大小是否可变Container c = getContentPane(); //获取窗体颜色c.setBackground(new Color(255, 221, 221,200)); //背景色c.setLayout(null);Font f1=new Font("黑体",Font.PLAIN,16);//根据指定字体名称、样式和磅值大小,创建一个新 Font。Font f2=new Font("楷体",Font.BOLD,18);Font f4=new Font("楷体",Font.BOLD,16);Font f3=new Font("黑体",Font.PLAIN,14);//发送文本域JTextArea jt = new JTextArea();  //文本域// jt.setText("点击右边发送键发送"); //提示语jt.setFont(f4); //设置字体格式JScrollPane jp = new JScrollPane(jt);  //滚动条jp.setBounds(50, 490, 420, 40);  //设置绝对位置c.add(jp);//显示文本域area = new JTextArea();area.setFont(f2); //设置字体格式area.setEditable(false);JScrollPane jpArea = new JScrollPane(area);  //滚动条jpArea.setBounds(50, 190, 510, 250);  //设置绝对位置c.add(jpArea);//消息区JLabel message = new JLabel();message.setFont(f2);message.setText("接收消息区");message.setBounds(50, 125, 140, 80);c.add(message);//在此输入您要发送的消息,点击右侧发送按钮发送JLabel sendmessage = new JLabel();sendmessage.setFont(f2);sendmessage.setText("在此输入您要发送的消息,点击右侧发送按钮发送");sendmessage.setBounds(50, 430, 500, 80);c.add(sendmessage);//目的IPJLabel desIp = new JLabel();desIp.setFont(f2);desIp.setText("目标IP:");desIp.setBounds(50, 20, 100, 80);c.add(desIp);JTextField desjt = new JTextField();desjt.setFont(f4);desjt.setBounds(140, 45, 150, 30);desjt.setText("127.0.0.1"); //设置默认IP地址desjt.setEditable(false);c.add(desjt);//目的端口JLabel desPo = new JLabel();desPo.setFont(f2);desPo.setText("目标端口:");desPo.setBounds(320, 20, 100, 80);c.add(desPo);JTextField desJtPo = new JTextField();desJtPo.setFont(f4);desJtPo.setBounds(405, 45, 150, 30);desJtPo.setText("0000"); //设置默认端口c.add(desJtPo);//你的昵称JLabel name = new JLabel();name.setFont(f2);name.setText("你的昵称:");name.setBounds(50, 75, 100, 80);c.add(name);JTextField jtName = new JTextField();jtName.setFont(f4);jtName.setBounds(140, 100, 150, 30);int num = (int) (Math.random()*100);String t = "未命名用户["+num+"]";jtName.setText(t);c.add(jtName);//本机端口JLabel myPo = new JLabel();myPo.setFont(f2);myPo.setText("本机端口:");myPo.setBounds(320, 75, 100, 80);c.add(myPo);JTextField jtmyPo = new JTextField();jtmyPo.setFont(f4);jtmyPo.setBounds(405, 100, 150, 30);jtmyPo.setEditable(false);c.add(jtmyPo);//绑定端口 建立连接JButton btnBind = new JButton("绑定端口 建立连接");btnBind.setBackground(new Color(255,221,221));btnBind.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {try {client.mainClient();//登录client.send("userName:"+jtName.getText());} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}//暂停进程 等待服务器返回数据try {Thread.sleep(1000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}System.out.println("***"+backMeg);//拿到绑定的本机端口号jtmyPo.setText(backMeg);}});btnBind.setBounds(405, 130, 150, 30);btnBind.setFont(f3);c.add(btnBind);//发送按钮JButton btn = new JButton("发送");btn.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {//String sendName = jtName.getText().equals("")?"I AM NULL":jtName.getText();String context = jt.getText().equals("")?"空空如也":jt.getText();context=context.replace('\n','$');jt.setText(""); //清空输入jt.requestFocus(); //获取光标String sendPort = desJtPo.getText(); //获取发送端口if(sendPort.equals("")) return;String name = jtName.getText();String sendMes = "P:" + sendPort +"-"+ name + "-" + context;System.out.println("发送框中的内容是:"+sendMes);client.send(sendMes);//暂停进程 等待服务器返回数据try {Thread.sleep(1000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}//System.out.println("发送后接收到的内容是:"+backMeg);//area.append(backMeg+"\n"); //文本内容增加}});btn.setBounds(490, 490, 70, 40);btn.setBackground(new Color(255,221,221));btn.setFont(f1);c.add(btn);setVisible(true); //可见}//美化图标public static void beautiful() {try {for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {if ("Nimbus".equals(info.getName())) {javax.swing.UIManager.setLookAndFeel(info.getClassName());break;}}}catch(Exception e) {System.out.println(e);}}public static void main(String[] args) {// TODO Auto-generated method stubbeautiful();client = new Client();new Frame();}
}

服务器端

package chat;import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;class Server implements Runnable{private static Map<String,Socket> map=new ConcurrentHashMap<>();private Socket socket;public Server(Socket socket){this.socket=socket;}@Overridepublic void run() {// 获取客户端的输入流try {Scanner scanner=new Scanner(socket.getInputStream());String msg=null;while(true){if(scanner.hasNextLine()){//处理客户端输入的字符串msg=scanner.next();System.out.println("服务器接收:"+msg);//用户登录流程,注册用户的格式为:userName:用户名if(msg.startsWith("userName:")){//将用户名或者端口号保存在userName中String userName=msg.split("\\:")[1];//注册该用户userRegist(userName,socket);continue;}//聊天信息,输入的格式为:P:port-userName-聊天信息else if(msg.startsWith("P:")&&msg.contains("-")){//保存需要聊天的目标端口、发送者昵称、发送的信息String port=msg.split("\\:")[1].split("-")[0];String name = msg.split("\\:")[1].split("-")[1];String str=msg.split("\\:")[1].split("-")[2];//发送聊天信息privateChat(port,name,str);continue;}}}} catch (IOException e) {e.printStackTrace();}}//登录 建立连接private void userRegist(String userName,Socket socket) throws IOException{//返回socket 值PrintStream printStream=new PrintStream(socket.getOutputStream());String port=socket.toString().split(",")[1].split("=")[1];printStream.println(port);map.put(port,socket); //将 [端口号,套接字] 存一份System.out.println("[用户名为"+userName+"][客户端为"+socket+"]上线了!");System.out.println("当前在线人数为:"+map.size()+"人");}/*** 私聊流程(利用port取得目标客户端的Socket对象,从而取得对应输出流,将私聊信息发送到指定客户端)* @param port 目标客户端端口号* @param userName 发送方的用户名* @param msg 要发送的信息*/private void privateChat(String port,String userName,String msg) throws IOException {//1.当前发送方客户端的用户名String curUser=userName;//2.取得私聊用户名对应的客户端Socket client=map.get(port);//3.获取私聊客户端的输出流,将私聊信息发送到指定客户端PrintStream printStream=new PrintStream(client.getOutputStream());Date date = new Date();SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");  //获得当前时间String m = formatter.format(date)+"@"+curUser+":"+msg;System.out.println(formatter.format(date));System.out.println(m);printStream.println(m);//socket.close();}}
public class MultiServer {public static void main(String[] args){try {//1.创建服务器端的ServerSocket对象,等待客户端连接ServerSocket serverSocket=new ServerSocket(9527);//2.创建线程池,从而可以处理多个客户端ExecutorService executorService= Executors.newFixedThreadPool(50);for(int i=0;i<50;i++){System.out.println("欢迎来到我的聊天室......");//3.侦听客户端Socket socket=serverSocket.accept();System.out.println("有新的朋友加入.....");//4.启动线程executorService.execute(new Server(socket));}//5.关闭线程池executorService.shutdown();//6.关闭服务器serverSocket.close();} catch (IOException e) {e.printStackTrace();}}
}

详细解析在另一篇给出:
[计算机网络实验4 - TCP套接字编程 - 点对点聊天 - 分析] - 找不到我吧我独一无二的博客 - CSDN博客

计算机网络实验4 - TCP套接字编程 - 点对点聊天 - 代码实现相关推荐

  1. 计算机网络实验:UDP套接字编程

    计算机网络实验:UDP套接字编程 一.安装实验环境 二.编写程序并调试程序 三.实验代码 一.安装实验环境 这次实验使用的是C/C++来编写套接字程序,可以安装DEVC++.VC6.0.CodeBlo ...

  2. 《计算机网络:自顶向下方法(原书第6版)》一2.7 TCP套接字编程

    本节书摘来华章计算机<计算机网络:自顶向下方法(原书第6版)>一书中的第2章 ,第2.7节,(美)James F.Kurose Keith W.Ross 著 陈 鸣 译 更多章节内容可以访 ...

  3. Experiment 0x1:TCP套接字编程

    Experiment 0x1:TCP套接字编程 文章目录 Experiment 0x1:TCP套接字编程 0x0 说明 0x1 要求 0x2 实现 0x3 源码 1- TCP服务端源码 2- TCP客 ...

  4. 套接字编程---2(TCP套接字编程的流程,TCP套接字编程中的接口函数,TCP套接字的实现,TCP套接字出现的问题,TCP套接字多进程版本,TCP套接字多线程版本)

    TCP模型创建流程图 TCP套接字编程中的接口 socket 函数 #include <sys/types.h> /* See NOTES */ #include <sys/sock ...

  5. tcp套接字编程模型

    1. tcp套接字编程 用下面的一张图可以清楚表示: 下面的python实现也很清晰: server: def tcplink(sock, addr):print 'Accept new connec ...

  6. 《网络编程》基本 TCP 套接字编程

    在进行套接字编程之前必须熟悉其地址结构,有关套接字的地址结构可参考文章<套接字编程简介>.基于 TCP 的套接字编程的所有客户端和服务器端都是从调用socket 开始,它返回一个套接字描述 ...

  7. 《UNIX网络编程 卷1:套接字联网API》学习笔记——基本TCP套接字编程

    UNIX网络编程--基本TCP套接字编程 socket 函数 connect 函数 bind 函数 listen 函数 accept 函数 fork 和 exec 函数 并发服务器 close 函数 ...

  8. UNIX环境编程(c语言)--套接字--基本TCP套接字编程

    目录 准备知识 字节序 字节序转换函数 字节操纵函数 地址转换函数 地址结构 基本TCP套接字编程 概要 socket函数 bind函数 listen函数 accept函数 connect函数 通信函 ...

  9. TCP套接字编程(C语言)

    本篇主要内容介绍: 介绍TCP套接字基本概念 介绍TCP套接字编程流程 基本TCP套接字函数介绍 1.TCP套接字基本概念(非官方解释,个人总结) 套接字是一种网络API,提供一种进程间的通信方法,使 ...

最新文章

  1. QT:(3)在VS2015下配置qt
  2. 配置oracle 11g环境,oracle 11g 的安装环境的配置
  3. Resources与StreamingAssets文件夹的区别
  4. Objective-C征途:Hello Objective-C
  5. 魔性十足的数学动态图,这种东西都拿出来分享?
  6. 阿里一面,说说你对Mysql死锁的理解
  7. java怎么看提示错误,Mabatis错误提示Parameter index out of range的处理方法
  8. Android JetPack –导航架构
  9. 《前沿视点》——2013年最值得关注的网页设计流行趋势
  10. 7-2 组织星期信息 (10 分)
  11. 汇编语言实模式到保护模式的思考
  12. ls命令输出的文件颜色
  13. linux看网卡ip,linux查看ip地址、显示太网卡配置、网络设备
  14. mysql uroot pg t_【原创】MySQL和PostgreSQL 导入数据对比
  15. Ubuntu使用问题(一):Ubuntu不能正常关机的解决方法
  16. 浅议-动态范围控制(DRC)
  17. springboot配置内存数据库H2
  18. 四川E900s-Hi3798MV100-黑盒8G版-黄标签高安版-5800-2AHPM6B-当贝桌面强刷卡刷包
  19. 用C语言实现打开一个网页
  20. Elasticsearch 断路器报错了,怎么办?

热门文章

  1. 使用Yolov5训练自己制作的数据集,快速上手
  2. 利用cocos2dx 3.2开发消灭星星(一)基本介绍
  3. html dt dd dl英文,dl dt dd是什么的缩写
  4. 南瓜科学好奇盒子上新 打造新时代玩具总动员
  5. SpringBoot整合Shiro实现RememberMe
  6. 人工智能——遗传算法
  7. Kubernetes的五种最佳安全实践
  8. 小马识途营销顾问解读百度官网认证的价值和意义
  9. 如何成为经济自由的创业者?翼牛科技手把手来教你!
  10. iOS 录音计时类似于秒表计时器的实现