计算机网络实验4 - TCP套接字编程 - 点对点聊天 - 代码实现
客户端
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套接字编程 - 点对点聊天 - 代码实现相关推荐
- 计算机网络实验:UDP套接字编程
计算机网络实验:UDP套接字编程 一.安装实验环境 二.编写程序并调试程序 三.实验代码 一.安装实验环境 这次实验使用的是C/C++来编写套接字程序,可以安装DEVC++.VC6.0.CodeBlo ...
- 《计算机网络:自顶向下方法(原书第6版)》一2.7 TCP套接字编程
本节书摘来华章计算机<计算机网络:自顶向下方法(原书第6版)>一书中的第2章 ,第2.7节,(美)James F.Kurose Keith W.Ross 著 陈 鸣 译 更多章节内容可以访 ...
- Experiment 0x1:TCP套接字编程
Experiment 0x1:TCP套接字编程 文章目录 Experiment 0x1:TCP套接字编程 0x0 说明 0x1 要求 0x2 实现 0x3 源码 1- TCP服务端源码 2- TCP客 ...
- 套接字编程---2(TCP套接字编程的流程,TCP套接字编程中的接口函数,TCP套接字的实现,TCP套接字出现的问题,TCP套接字多进程版本,TCP套接字多线程版本)
TCP模型创建流程图 TCP套接字编程中的接口 socket 函数 #include <sys/types.h> /* See NOTES */ #include <sys/sock ...
- tcp套接字编程模型
1. tcp套接字编程 用下面的一张图可以清楚表示: 下面的python实现也很清晰: server: def tcplink(sock, addr):print 'Accept new connec ...
- 《网络编程》基本 TCP 套接字编程
在进行套接字编程之前必须熟悉其地址结构,有关套接字的地址结构可参考文章<套接字编程简介>.基于 TCP 的套接字编程的所有客户端和服务器端都是从调用socket 开始,它返回一个套接字描述 ...
- 《UNIX网络编程 卷1:套接字联网API》学习笔记——基本TCP套接字编程
UNIX网络编程--基本TCP套接字编程 socket 函数 connect 函数 bind 函数 listen 函数 accept 函数 fork 和 exec 函数 并发服务器 close 函数 ...
- UNIX环境编程(c语言)--套接字--基本TCP套接字编程
目录 准备知识 字节序 字节序转换函数 字节操纵函数 地址转换函数 地址结构 基本TCP套接字编程 概要 socket函数 bind函数 listen函数 accept函数 connect函数 通信函 ...
- TCP套接字编程(C语言)
本篇主要内容介绍: 介绍TCP套接字基本概念 介绍TCP套接字编程流程 基本TCP套接字函数介绍 1.TCP套接字基本概念(非官方解释,个人总结) 套接字是一种网络API,提供一种进程间的通信方法,使 ...
最新文章
- QT:(3)在VS2015下配置qt
- 配置oracle 11g环境,oracle 11g 的安装环境的配置
- Resources与StreamingAssets文件夹的区别
- Objective-C征途:Hello Objective-C
- 魔性十足的数学动态图,这种东西都拿出来分享?
- 阿里一面,说说你对Mysql死锁的理解
- java怎么看提示错误,Mabatis错误提示Parameter index out of range的处理方法
- Android JetPack –导航架构
- 《前沿视点》——2013年最值得关注的网页设计流行趋势
- 7-2 组织星期信息 (10 分)
- 汇编语言实模式到保护模式的思考
- ls命令输出的文件颜色
- linux看网卡ip,linux查看ip地址、显示太网卡配置、网络设备
- mysql uroot pg t_【原创】MySQL和PostgreSQL 导入数据对比
- Ubuntu使用问题(一):Ubuntu不能正常关机的解决方法
- 浅议-动态范围控制(DRC)
- springboot配置内存数据库H2
- 四川E900s-Hi3798MV100-黑盒8G版-黄标签高安版-5800-2AHPM6B-当贝桌面强刷卡刷包
- 用C语言实现打开一个网页
- Elasticsearch 断路器报错了,怎么办?