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

运行结果:



最新文章

  1. JavaScript面试时候的坑洼沟洄——数据类型
  2. html页面输入框input的美化
  3. SpreadJS 中应用 KnockoutJS 技术
  4. Reduce对Pig作业性能的影响
  5. 一步步学习ASP.NET MVC3 (13)——HTML辅助方法
  6. 共享式以太网与交换式以太网的性能比较(OPNET网络仿真实验)
  7. line
  8. bzoj 1217: [HNOI2003]消防局的设立
  9. 升级node版本
  10. 正则表达式匹配html标签里面的内容
  11. 常用vi编辑器命令
  12. Day28--Python--网络通信协议 tcp与udp下的socket
  13. HDU 1017(** **)
  14. 解决vue.js在编写过程中出现空格不规范报错的情况
  15. Django Model 进阶
  16. Docker学习笔记之Copy on Write机制
  17. php中错误处理机制
  18. rabbitmq系列四 之路由
  19. 基于Ionic的移动框架搭建
  20. Python的scrapy之爬取6毛小说网的圣墟

热门文章

  1. IntelliJ IDEA2021.2 常用快捷键汇总总结
  2. CentOS7.9安装Oracle 12C数据库实战
  3. 创建多个Dialog时,namespace冲突问题的解决 -- 基于QT 5.2
  4. IO多路复用详解
  5. 实战 | Hive 数据倾斜问题定位排查及解决
  6. oracle控制用户权限命令
  7. Bugku-你必须让他停下来
  8. 内置函数 strlen
  9. 时间转换 BASIC-14
  10. JVM学习笔记-第六章-类文件结构