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. 客户端:

  ```java
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;
}
}

运行结果:



Java网络编程之TCP的更多相关文章

  1. Java网络编程之TCP、UDP

    Java网络编程之TCP.UDP 2014-11-25 15:23 513人阅读 评论(0) 收藏 举报 分类: java基础及多线程(28) 版权声明:本文为博主原创文章,未经博主允许不得转载.   ...

  2. java网络编程之TCP通讯

    java中的网络编程之TCP协议的详细介绍,以及如何使用,同时我在下面举2例说明如何搭配IO流进行操作, /* *TCP *建立连接,形成传输数据的通道: *在连接中进行大数据量传输: *通过三次握手 ...

  3. Java网络编程之TCP通信

    一.概述 Socket类是Java执行客户端TCP操作的基础类,这个类本身使用代码通过主机操作系统的本地TCP栈进行通信.Socket类的方法会建立和销毁连接,设置各种Socket选项. Server ...

  4. java 网络编程之TCP通信和简单的文件上传功能

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  5. 4.Java网络编程之TCP/UDP

    常见传输协议: UDP , TCP UDP协议:    特点:         1.将数据及源和目的封装成数据包中,不需要建立连接         2.每个数据包的大小限制在64K内         ...

  6. java网络编程之TCP实例

    Dgram类 package Socket; import java.net.DatagramPacket; import java.net.InetAddress; public class Dgr ...

  7. 网络编程之TCP编程

    网络编程之TCP编程 前面已经介绍过关于TCP协议的东西,这里不做赘述.Java对于基于TCP协议的网络通信提供了良好的封装,Java使用socket对象来代表两端的通信窗口,并通过Socket产生I ...

  8. Java网络编程之InetAddress浅析

    Java网络编程之InetAddress浅析 一.InetAddress综述 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetA ...

  9. Python网络编程之TCP套接字简单用法示例

    Python网络编程之TCP套接字简单用法示例 本文实例讲述了Python网络编程之TCP套接字简单用法.分享给大家供大家参考,具体如下: 上学期学的计算机网络,因为之前还未学习python,而jav ...

随机推荐

  1. 虚拟机安装的kali操作系统实现共享文件夹

    虚拟机共享文件夹设置. 1.[虚拟机]-->[设置] 2.先在本地新建一个共享文件夹,然后将此文件夹的路径添加到虚拟机 3.进入kali操作系统,运行命令sudo vmhgfs-fuse .ho ...

  2. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  3. .NET5控制台程序使用EF连接MYSQL

    .NET5控制台程序使用EF连接MYSQL 1.使用nuget下载: Microsoft.Extensions.Configuration.Json Pomelo.EntityFrameworkCor ...

  4. 3个月零基础入门Python+数据分析,详细时间表+计划表分享

    ​大家好,我是白云. 今天想给大家分享的是三个月零基础入门数据分析学习计划.有小伙伴可能会说,英语好像有点不太好,要怎么办?所以今天我给大家分享的资源呢就是对国内的小伙伴很友好,还附赠大家一份三个月学 ...

  5. RHCSA_DAY04

    软连接与硬连接 Linux中的链接文件类似于windows中的快捷方式 软连接特点:软连接可以跨分区,可以对目录进行链接,源文件删除后,链接文件不可用 软连接命令格式:ln -s 源文件路径  目标路 ...

  6. python UI自动化之鼠标事件

    使用 pyautogui 模块:import pyautogui 1. 鼠标移动至:1629,875是电脑屏幕坐标:0.25是移动时间 pyautogui.moveTo(1629,875, durat ...

  7. Android开发失业六个月了,无限的焦虑

    最近到网上看到这样一个帖子: Android开发,坐标魔都:目前为止已经失业六个月,找工作期间,尤其是最近两天确实心态不好.要么没有面试,要么给的工资不符合预期( hr 压价太狠了,原先说的 19k, ...

  8. 获取元素在页面中位置 getBoundingClientRect()

    DOM 原生方法getBoundingClientRect()获取元素相对视口位置 DOMRect 对象包含了一组用于描述边框的只读属性--left.top.right和bottom,单位为像素.除了 ...

  9. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事(11.B)- FlexSPI NOR连接方式大全(RT1160/1170)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MXRT1160/1170两款MCU的FlexSPI NOR启动的连接方式. 这个 i.MXRT FlexSPI NOR 启动 ...

  10. Postman API 接口测试、Jenkin 持续集成测试

    Postman 是一个创建和使用API的应用,Postman 对于Web开发者来说非常有用,Postman 带来的便利有很多,诸如: RESTFul接口测试不依赖其他端,进度不受影响 测试脚本即文档, ...