1

我首先使用线程和套接字,所以我正在尝试进行聊天(本地)

ClientA(实际上是服务器):

public class ClientA {

    public static void main(String[] args) {

        ServerSocket servsock = null;
        try {
            servsock = new ServerSocket(9998);
            Socket conn = servsock.accept();
            System.out.println("server socket listening on local port : " + servsock.getLocalPort());
            System.out.println("socket listening on local port : " + conn.getLocalPort());
            System.out.println("socket listening on port : " + conn.getPort());
            servsock.close();

            TReadingSock tls = new TReadingSock(conn);
            tls.start();
            TWritingSock tes = new TWritingSock(conn);
            tes.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户 B,实际客户:

public class ClientB {

    public static void main(String[] args) {

        Socket sock = null;
        try {
            sock = new Socket("localhost", 9998);
            System.out.println("socket listening on local port : " + sock.getLocalPort());
            System.out.println("socket listening on port : " + sock.getPort());
        } catch (IOException e) {
            e.printStackTrace();
        }

        TReadingSock tls = new TReadingSock(sock);
        tls.start();
        TWritingSock tes = new TWritingSock(sock);
        tes.start();
    }
}

打印显示:

客户甲:

server socket listening on local port : 9998
socket listening on local port : 9998 
socket listening on port : 50875

客户乙:

socket listening on local port : 50875  
socket listening on port : 9998

因此,尽管看起来很愚蠢,但我在理解整个套接字方面存在严重问题,我唯一得到的就是我的程序正在侦听不同的端口,我不明白为什么。我想这对某些人来说一定很明显,所以我请求你的帮助来启发我!

提前致谢。

编辑:感谢您的所有回答。问题是,对我来说,您需要一个 ServerSocket 来侦听端口并接受任何尝试连接的客户端。完成后,它返回一个 Socket 对象,我将其传递给我的线程,以便它们可以完成工作。那是给客户A的。客户端 B 只是创建一个 Socket,它将尝试连接到 9998 端口,这是我用我的 ServerSocket 监听的端口。然后它将它传递给它的线程。问题是,当我启动我的客户端(A 然后 B)并在控制台 A 中写入时,控制台 B 上没有任何反应(也许我应该早点指定,抱歉)。

我猜这是由于我的套接字正在使用的端口。我检查了一些教程,即使在阅读了您的回复之后,我也看不出有什么问题,所以要么我遗漏了一些非常明显的概念,要么它不是连接本身,而是我处理连接的方式。以防万一,我将发布线程的内容:

public class TWritingSock extends Thread {
    private Socket sockw;

    public TWritingSock(Socket sockw){
        this.sockw = sockw;
    }

    @Override
    public void run(){
        try {
            while(true){
                //Recuperation des saisies clavier
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                //Ecriture de la saisie
                PrintWriter pw= new PrintWriter(sockw.getOutputStream(), true);

                String typed = br.readLine();
                if(typed.equals("fin")){
                    //sockw.close();
                    System.out.println("fermé");
                    break;
                }
                pw.write(typed);
            }           
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                sockw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    } 
}

public class TReadingSock extends Thread {
    private Socket sockr;

    public TReadingSock(Socket sockr){
        this.sockr = sockr;
    }

    @Override
    public void run(){
        try {
            while(true){
                BufferedReader br = new BufferedReader(new InputStreamReader(sockr.getInputStream()));
                String typed = br.readLine();
                if(typed.equals("fin")){
                    //sockr.close();
                    System.out.println("fermé");
                    break;
                }
                System.out.println(typed);
            }   
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                sockr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
4

3 回答 3

2

(我将使用粗略和简单的图像来谈论 Socket,请把它看作是我试图尽可能简单地解释这一点。)

将 Socket 视为隧道。现在,如果我告诉你我的隧道尽头是 9998,那么你就可以到达它,但这条隧道的尽头可以是任何东西,由你决定。

ClientA(实际上是服务器)说“我想在端口 9998 上监听”。当 ClientA 连接“好的,我们已连接,我在端口 9998 上,你在 50875 上。”。

ClientB 说“我想访问你的端口 9998,我将使用我的端口 50875 来做。”

两个应用程序现在都可以通过隧道进行通信,因为它们知道隧道的去向。

于 2013-05-29T14:01:00.390 回答
1

Internet 上的每个 TCP 连接由两对或四个元素组成:端点 A IP 地址、端点 A 端口号和端点 B IP 地址、端点 B 端口。在传输层,地址在IP 数据包头中指定,而端口在TCP 头中注明。这允许明确识别主机和进程(通过端口)以将数据包传递到。

bind()您侦听“服务器”套接字时,您可以修复该端点端口号(在您的情况下为 9998)。当客户端连接到达时,其他三个部分也固定 - 您的本地 IP 是连接到达的网络接口,远程 IP 和端口是连接客户端的,其中端口通常由操作系统从临时端口池,在您的示例中为 50875。

于 2013-05-29T14:05:41.827 回答
0

好的,让我试着让你更容易理解这些概念。因此,当您阅读本教程时,一切都会变得有意义。

套接字用非常简单的术语来说就是客户端和服务器之间的隧道。一个读,另一个写。换句话说,当一个等待读取时,另一个写入隧道。当读取成功后,数据就可以被接收方处理了。

这里客户端和服务器都可以进行双向通信。有些人创建了一种锯齿形模式,服务器等待读取,客户端发送数据并进入读取等待,服务器处理它并响应客户端。客户端显示成功/错误。以此类推。

在他们可以进行读写之前,他们形成了一个连接。为了建立连接,他们需要告诉对方他们的身份(IP 地址/DNS)是什么。

到这一步了?

如果您需要我解释端口,请告诉我。

于 2013-05-29T14:01:29.890 回答