Socket编程一实现简易的聊天功能以及文件传输.docx

上传人:b****3 文档编号:12890640 上传时间:2023-04-22 格式:DOCX 页数:12 大小:414.70KB
下载 相关 举报
Socket编程一实现简易的聊天功能以及文件传输.docx_第1页
第1页 / 共12页
Socket编程一实现简易的聊天功能以及文件传输.docx_第2页
第2页 / 共12页
Socket编程一实现简易的聊天功能以及文件传输.docx_第3页
第3页 / 共12页
Socket编程一实现简易的聊天功能以及文件传输.docx_第4页
第4页 / 共12页
Socket编程一实现简易的聊天功能以及文件传输.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Socket编程一实现简易的聊天功能以及文件传输.docx

《Socket编程一实现简易的聊天功能以及文件传输.docx》由会员分享,可在线阅读,更多相关《Socket编程一实现简易的聊天功能以及文件传输.docx(12页珍藏版)》请在冰豆网上搜索。

Socket编程一实现简易的聊天功能以及文件传输.docx

Socket编程一实现简易的聊天功能以及文件传输

Socket编程一实现简易的聊天功能以及文件传输

功能效果图:

可以这里使用多台手机进行通讯,【凤歌】我采用的服务器发送消息。

是不是只有发送消息,有些显得太单调了。

好,在发送消息的基础上增加文件传输。

后期会增加视频,音频的传输,增加表情包。

那一起来看看图文消息的效果图,带领大家一起来实现通讯的简易聊天功能。

需要解决的难点:

如何判断socket接收的数据是字符串还是流?

如果你已是一名老司机,还请留言给出宝贵意见。

带着这个疑问我们接着往下看。

Socket概述

Socket我们称之为”套接字”,用于消息通知系统(如:

激光推送),时事通讯系统(如:

环信)等等。

用于描述IP地址和端口,是一个通信链的句柄。

网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定(如:

ServerSocket)。

应用程序通常通过”套接字”向网络发出请求或者应答网络请求。

Socket是TCP/IP协议的一个十分流行的编程界面,但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。

在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

java.NET包下有两个类:

Socket和ServerSocket,基于TCP协议。

本文针对Socket和ServerSocket作主要讲解。

socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。

套接字之间的连接过程分为三个步骤:

服务器监听,客户端请求,连接确认。

步骤如下:

服务器监听:

服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求

客户端请求:

指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。

为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:

当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。

而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

JDKSocket

在java.Net包下有两个类:

Socket和ServerSocket。

ServerSocket用于服务器端,Socket是建立网络连接时使用的。

在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。

对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。

不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

接着了解下Socket和ServerSocket的构造方法。

Socket

Socket的构造方法:

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

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

Socket(InetAddressaddress,intport,InetAddresslocalAddr,intlocalPort);//创建一个套接字并将其连接到指定远程地址上的指定远程端口

Socket(Stringhost,intport,InetAddresslocalAddr,intlocalPort);//创建一个套接字并将其连接到指定远程主机上的指定远程端口

Socket(SocketImplimpl);//使用用户指定的SocketImpl创建一个未连接Socket

参数含义:

address双向连接中另一方的IP地址

port端口号

localPort本地主机端口号

localAddr本地机器地址

impl是socket的父类,既可以用来创建serverSocket又可以用来创建Socket

注意:

我们在选取端口号的时候需要特别注意,每一个端口提供一种特定的服务,只有给出正确的端口,才能获得相应的服务。

0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23。

本文选取的端口号为30003

Socket的几个重要方法:

publicInputStreamgetInputStream();//方法获得网络连接输入,同时返回一个IutputStream对象实例

publicOutputStreamgetOutputStream();//方法连接的另一端将得到输入,同时返回一个OutputStream对象实例

publicSocketaccept();//用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。

对流的操作,操作完记得处理和关闭。

以及对流异常的处理。

ServerSocket

ServerSocket的构造方法:

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

ServerSocket(intport,intbacklog);//利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号

ServerSocket(intport,intbacklog,InetAddressbindAddr);//使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器

接着我们一起来看看案例。

发送和接收消息

首先来实现一个简单的案例,服务器端一直监听某个端口,等待客户端连接请求。

客户端根据IP地址和端口号连接服务器端,接着客服端通过控制台向服务端发送消息,服务端接收到消息并且展示出来。

下面来看看具体实现的步骤:

ClientSocket客服端:

try{

Socketsocket=newSocket("173.1.1.121",30004);

//获取控制台输入的内容

BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(System.in));

System.out.print("请输入发送的字符串:

");

Stringstr=bufferedReader.readLine();

//给服务端发送消息

PrintWriterprintWriter=newPrintWriter(socket.getOutputStream());

printWriter.write(str+"\r\n");

printWriter.flush();

//关闭资源

bufferedReader.close();

printWriter.close();

socket.close();

}catch(IOExceptione){

e.printStackTrace();

}

Socket两个参数分别是IP地址和端口号,可以通过以下代码获取IP地址:

InetAddressia=null;

try{

ia=ia.getLocalHost();

Stringlocalname=ia.getHostName();

Stringlocalip=ia.getHostAddress();

System.out.println("本机名称是:

"+localname);

System.out.println("本机的ip是:

"+localip);

}catch(Eceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

注意:

关闭多余的网络适配,只保留当前的网络连接。

关闭防火墙,安全软件。

不然可能导致连接不上。

ServerSocket服务端:

try{

mServerSocket=new.ServerSocket(30004);

Socketsocket=mServerSocket.accept();

BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(socket.getInputStream()));

Stringcontent=null;

while((content=bufferedReader.readLine())!

=null){

System.out.println("接收到客服端发来的消息:

"+content);

}

//关闭连接

bufferedReader.close();

socket.close();

}catch(IOExceptione){

e.printStackTrace();

}

服务端和客服端的端口号必须保持一致。

下面我们运行两个java程序看看效果:

传输文件

Socket只能通过流去读取消息,传输文件需要解决文章开始提出的问题,如何判断socket接收的数据是字符串还是流?

定义协议

为了保证接收到的数据类型统一(数据是字符串还是流),需要定义协议。

定义协议的方式有很多种:

发送一个握手信号。

根据握手信号来确定发送的是字符串还是流

定义了Header(头)和Body(实体),头是固定大小的,用来告诉接收者数据的格式、用途、长度等信息,接收者根据Header来接受Body。

自定义协议

我这里采用的自定义协议,原理跟前面两种类似。

我传输的是JSON数据,根据字段标识传输的是字符串还是流,接收者根据标识去解析数据即可。

协议的实体类(Transmission):

//文件名称

publicStringfileName;

//文件长度

publiclongfileLength;

//传输类型

publicinttransmissionType;

//传输内容

publicStringcontent;

//传输的长度

publiclongtransLength;

//发送还是接受类型1发送2接收

publicintitemType=1;

//0文本1图片

publicintshowType;

根据字段transmissionType去标识传输(序列化)或接收(反序列化)的类型。

传输的过程中始终都是以JSON的格式存在的。

传输文件时需要把流转换成字符串(方式很多种我用的是Base64加密与解密)。

客户端(ClientThread)

客户端发送文件的代码如下:

/**

*文件路径

*

*@paramfilePath

*/

privatevoidsendFile(StringfilePath){

FileInputStreamfis=null;

Filefile=newFile(filePath);

try{

mSendHandler.sendEmptyMessage(Constants.PROGRESS);

fis=newFileInputStream(file);

Transmissiontrans=newTransmission();

trans.transmissionType=Constants.TRANSFER_FILE;

trans.fileName=file.getName();

trans.fileLength=file.length();

trans.transLength=0;

byte[]bytes=newbyte[1024];

intlength=0;

while((length=fis.read(bytes,0,bytes.length))!

=-1){

trans.transLength+=gth;

trans.content=Base64Utils.encode(bytes);

mPrintWriter.write(mGson.toJson(trans)+"\r\n");

mPrintWriter.flush();

//更新进度

Messagemessage=newMessage();

message.what=Constants.PROGRESS;

message.obj=100*trans.transLength/trans.fileLength;

mSendHandler.sendMessage(message);

}

fis.close();

}catch(FileNotFoundExceptione){

e.printStackTrace();

if(fis!

=null){

try{

fis.close();

}catch(IOExceptione1){

e1.printStackTrace();

}

}

}catch(IOExceptione){

e.printStackTrace();

mPrintWriter.close();

}

}

文章结尾处我会附上源码。

trans.content=Base64Utils.encode(bytes);

mPrintWriter.write(mGson.toJson(trans)+"\r\n");

mPrintWriter.flush();

把字节流转换成字符串传输Base64Utils.encode(bytes),接收方把字符串解析成字节流并写入文件。

注意:

在Android程序中运行,记得添加网络文件读写的权限。

服务端(ServerThread)

服务端接收文件的代码如下:

longfileLength=trans.fileLength;

longtransLength=trans.transLength;

if(mCreateFile){

mCreateFile=lse;

fos=newFileOutputStream(newFile("d:

/"+trans.fileName));

}

byte[]b=Base64Utils.decode(trans.content.getBytes());

fos.write(b,0,b.length);

System.out.println("接收文件进度"+100*transLength/fileLength+"%...");

if(transLength==fileLength){

mCreateFile=true;

fos.flush();

fos.close();

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 营销活动策划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1