0


Java网络编程——TCP

什么是Socket?

在开发网络应用程序的时候,会遇到Socket这个概念。Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。

Socket、TCP和部分IP的功能都是由操作系统提供的,不同的编程语言只是提供了对操作系统调用的简单的封装,例如,Java提供的几个Socket相关的类就封装了操作系统提供的接口:ServerSocket类,Socket类。

为什么需要Socket进行网络通信?

因为仅仅通过IP地址进行通信是不够的,同一台计算机同一时间会运行多个网络应用程序。当操作系统抽象出Socket接口,每个应用程序需要各自对应到不同的Socket,数据包才能根据Socket正确地发到对应的应用程序。

一个Socket就是由IP地址和端口号(范围065535)组成,可以把Socket简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个065535之间的数字,其中,小于1024的端口属于特权端口。需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。

使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器和客户端就成功的建立了一个TCP连接,双方后续就可以随时发送和接收数据。

因此,当Socket连接成功地在服务器和客户端之间建立后:

1、对服务器端来说,它的Socket是指定的IP地址和指定的端口号;

2、对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

注:

TCP协议是一种可靠、面向连接的协议,而TCP编程依靠于TCP协议,通过Socket来建立连接。

TCP编程实例:

TCP编程实现游戏人物选角

服务器端:

先创建一个List集合,用来存放人物角色,再创建一个Map集合,用来存放玩家与对应的人物角色<玩家,人物角色>。

再创建一个ServerSocket对象,通过while(true)死循环来使服务器一直运行。使用accept()方法来接收客户端对象,返回一个Socket对象。通过输入流来获取客户端发来的选角请求。通过输出流将人物角色返回至Socket并且反馈给客户端。

在获取玩家姓名时,先判断是否为空,如果为空则显示"【获取角色失败,请输入正确的玩家姓名】",如果不为空判断玩家姓名是否重复,如果玩家姓名重复则显示"【该玩家已存在!】",最后判断人物角色是否分配完成(List 集合是否为空【当人物角色被选择则会在List集合中将此角色删除,从而避免角色被重复分配】)若人物角色分配完成则显示"【角色分配完成,游戏开始~】"。

代码实现:

package com.hwh.demo1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class CharacterServer {
    public static void main(String[] args) {
        List<String> role=new ArrayList<String>() {
            {
                add("圣女");add("下毒者");add("杀手");add("士兵");
                add("市长");add("洗衣妇");add("间谍");add("图书管理员");
                add("守鸦人");add("小恶魔");add("酒鬼");add("厨师");
                add("调查员");add("男爵");add("隐士");add("共情者");
                add("占卜师");add("僧侣");add("管家");add("圣徒");add("猩红女郎");                
            }
        };
        Map<String, String> map=new LinkedHashMap<String, String>();
        try (ServerSocket server = new ServerSocket(3333)) {
            while(true) {
                Socket client=server.accept();
                String clientIp=client.getInetAddress().getHostAddress();
                try(BufferedReader reader=new BufferedReader(new InputStreamReader(client.getInputStream()));
                BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
                    //来自玩家的选角
                    String player=reader.readLine().trim();
                    
                    if(player.length()!=0) {
                        if(role.isEmpty()) {
                            writer.write("【角色分配完成,游戏开始~】");
                            writer.newLine();
                            writer.flush();
                        }else {
                            if(!map.containsKey(player)){
                                System.out.println("来自玩家:"+player+"的选角");
                                
                                //获取(随机下标)玩家角色
                                int index=(int)(Math.random()*role.size());
                                String character=role.get(index);
                                map.put(player, character);
                                role.remove(index);
                                
                                 //发送角色至玩家
                                writer.write(character);
                                writer.flush();
                                }else {
                                  writer.write("【该玩家已存在!】");
                                  writer.flush();
                                }
                        }
                        
                    }else {
                        writer.write("【获取角色失败,请输入正确的玩家姓名】");
                        writer.flush();
                    }
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }

}

客户端:

先创建一个Socket对象。将服务器端的IP 地址和端口号传入对象中,通过Scanner在控制台输入玩家姓名;

根据人物角色的个数来设置客户端循环的次数,避免循环过多。

然后通过输出流将请求发给Socket对象并反馈给服务器端,发送完后调用shutdownOutput()这个方法暂时结束本次输出。

服务器接收到请求后将人物角色发送Socket对象并且返回给客户端,客户端通过输入流接收到信息。

代码实现:

package com.hwh.tcp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class PlayerClient {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        System.out.println("请输入玩家姓名:");
        int i=0;
        while(i++<=21) {
            try (Socket client=new Socket("192.168.254.189",3333);
                BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
                BufferedReader reader=new BufferedReader(new InputStreamReader(client.getInputStream()))){
                //从控制台获取输入的玩家姓名
                String player=input.nextLine();
                if(player.length()!=0) {
                    //发送玩家姓名至角色
                    writer.write(player);
                    writer.flush();
                    //暂时结束本次输出
                    client.shutdownOutput();
                    //获取玩家的角色
                    String character=reader.readLine();
                    if(character.equals("【角色分配完成,游戏开始~】")) {
                        System.out.println(character);
                    }else if(character.equals("【获取角色失败,请输入正确的玩家姓名】")){
                        System.out.println(character);
                    }else if(character.equals("【该玩家已存在!】")){
                        System.out.println(character);
                    }else{
                        System.out.println("您获得的角色为:"+character);
                    }
                }
                

            
            } catch (IOException e) {
                
                e.printStackTrace();
            }
            
            
        }
    }

}

运行结果:


本文转载自: https://blog.csdn.net/weixin_49137294/article/details/125825276
版权归原作者 鸣筝鸣筝 所有, 如有侵权,请联系我们删除。

“Java网络编程&mdash;&mdash;TCP”的评论:

还没有评论