用java编写一个聊天程序_基于JAVA实现的一个简单的网络聊天程序

一、Java Socket的概述

1、Socket套接字方便了开发网络应用程序。TCP面向连接的可靠传输协议、具有数据确认和数据重传机制。保证了发送数据一定能到达通信的对方。UPD协议无连接,不可靠的传输协议。不具有数据确认和数据重传机制。socket是套接字的意思,一般用来描述IP地址和端口,是一个通信链的句柄。应用程序通常通过套接字向网络发出请求或者应答网络请求。摘一段比喻,有助于理解。socket非常类似于电话插座。以一个国家级电话网为例。电话的通话双方相当于相互通信的2个进程,区号是它的网络地址:区内一个单位的交换机相当于一台主机,主机分配给每个用户的局内号码相当于socket号。任何用户在通话之前,首先要占有一部电话机。相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连接请求。

2、 Socket是著名的网络应用编程接口(API)之一,而Java语言是网络编程的主要语言,提供了强大和独特的网络通讯支持机制和能力。Socket机制成功的解决了两台主机不同进程之间的通信问题。Socket通信机制它采用客户服务器模式,由服务器方先建立自己的半相关(建立Socket并将Socket联编到某个端口上),并进入监听状态,同时监听是否有与自己端口相对应的连接请求。连接是客户方发送的。客户方在建立自己的半相关后,向服务器发起连接(调用方法conmect(),服务器在检测到连接后,接受连接(调用方法accept()),这样就建立起来一个完整的连接。

二、ServerSocket类和Socket类的常用方法

Socket类

Socket(InetAddress address, intport) 创建一个流套接字并将其连接到指定IP地址的指定端口号。

Socket(String host,intport) 创建一个流套接字并将其连接到指定主机上的指定端口号。

Socket(InetAddress address,int port, InetAddress localAddr, intlocalPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。

Socket(String host,int port, InetAddress localAddr, intlocalPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。

close() 关闭此套接字。

connect(SocketAddress endpoint) 将此套接字连接到服务器。

connect(SocketAddress endpoint,inttimeout) 将此套接字连接到服务器,并指定一个超时值。

getInetAddress() 返回套接字连接的地址。

getInputStream() 返回此套接字的输入流。

getLocalPort() 返回此套接字绑定到的本地端口。

getOutputStream() 返回此套接字的输出流。

getPort() 返回此套接字连接到的远程端口。

ServerSocket类

ServerSocket(intport) 创建绑定到特定端口的服务器套接字。

accept() 侦听并接受到此套接字的连接。

getInetAddress() 返回此服务器套接字的本地地址。

三、TCP通信

ec47d3ba3c6b4558aa645de71d9cd0b8.png

服务器端步骤:

1、创建ServerSocket对象,绑定监听端口。

2、通过accept()方法监听客户端请求。

3、连接建立后,通过输入流读取客户端发送的请求信息。

4、通过输出流向客户端发送响应信息。

5、关闭响应的资源。

客户端步骤:

1、创建Socket对象,指明需要连接的服务器的地址和端口号。

2、连接建立后,通过输出流向服务器发送请求信息。

3、通过输入流获取服务器响应的信息。

4、关闭相应资源。

四、代码实现

服务端:

packagetest;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.net.ServerSocket;importjava.net.Socket;public classServer {public static void main(String[] args) throwsIOException {//建立tcp的服务端

ServerSocket serverSocket = new ServerSocket(9090);//接受客户端的连接,产生一个Socket

Socket socket =serverSocket.accept();//获取到Socket的输入流对象

BufferedReader socketReader = new BufferedReader(newInputStreamReader(socket.getInputStream()));//获取到Socket输出流对象

OutputStreamWriter socketOut = newOutputStreamWriter(socket.getOutputStream());//获取键盘的输入流对象

BufferedReader keyReader = new BufferedReader(newInputStreamReader(System.in));//读取客户端的数据

String line = null;while((line = socketReader.readLine())!=null){

System.out.println("客户端:"+line);

System.out.println("服务端:");

line=keyReader.readLine();

socketOut.write(line+"\r\n");

socketOut.flush();

}

serverSocket.close();

}

}

客户端:

packagetest;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.net.InetAddress;importjava.net.Socket;//聊天的客户端

public classClient {public static void main(String[] args) throwsIOException {//建立tcp的客户端服务

Socket socket = new Socket(InetAddress.getLocalHost(),9090);//获取socket的输出流对象。

OutputStreamWriter socketOut = newOutputStreamWriter(socket.getOutputStream());//获取socket的输入流对象

BufferedReader socketReader = new BufferedReader(newInputStreamReader(socket.getInputStream()));//获取键盘的输入流对象,读取数据

BufferedReader keyReader = new BufferedReader(newInputStreamReader(System.in));

String line= null;//不断的读取键盘录入的数据,然后把数据写出

System.out.print("客户端:");while((line = keyReader.readLine())!=null){

socketOut.write(line+"\r\n");

socketOut.flush();//读取服务端回送的数据

line =socketReader.readLine();

System.out.println("服务端:"+line);

}

socket.close();

}

}

五、实验结果

9d37ed2de23d148a2f905ca3675a7ab7.png

ab6fbeae8d9dc9bb8c4a81c4de82c85c.png

六、Linux与网络编程相关的函数

int socket(int domain, int type,intprotocol)

domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等)。 AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程

主机之间通信(当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为glibc是posix的实现 所以用PF代替了AF,不过我们都可以使用的)。

type:我们网络程序所采用的通讯协议(SOCK_STREAM, SOCK_DGRAM等) SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流。

SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信。

protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了 socket为网络通讯做基本的准备。成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情。

int bind(int sockfd, struct sockaddr *my_addr, intaddrlen)

sockfd:是由socket调用返回的文件描述符。

addrlen:是sockaddr结构的长度。my_addr:是一个指向sockaddr的指针。 在其中有 sockaddr的定义:structsockaddr{

unisgnedshortas_family;char sa_data[14];

};

int listen(int sockfd,intbacklog)

sockfd:是bind后的文件描述符。

backlog:设置请求排队的最大长度。当有多个客户端程序和服务端相连时,使用这个表示可以介绍的排队长度。listen函数将bind的文件描述符变为监听套接字。返回的情况和bind一样。

int accept(int sockfd, struct sockaddr *addr,int *addrlen)

sockfd:是listen后的文件描述符。

addr, addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了。 bind,listen和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个

客户程序发出了连接。

accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了。失败时返回-1。

int connect(int sockfd, struct sockaddr * serv_addr,intaddrlen)

sockfd:socket返回的文件描述符。

serv_addr:储存了服务器端的连接信息。其中sin_add是服务端的地址

addrlen:serv_addr的长度

connect函数是客户端用来同服务端连接的。成功时返回0,sockfd是同服务端通讯的文件描述符 失败时返回-1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值