写道
socket相关知识
1.socket的定义:
所谓socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 以J2SDK-1.6为例,Socket和ServerSocket类库位于java .net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。
2.Socket API (比较重量级的api)
accept()方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。
getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例。getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。 注意:其中getInputStream和getOutputStream方法均可能会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。
写道
常用的Socket类型
有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 Socket建立为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:int socket(int domain, int type, int protocol);domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值0。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。 Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。 Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。
有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 Socket建立为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:int socket(int domain, int type, int protocol);domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值0。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。 Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。 Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。
写道
开发原理:
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024---65535的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024---65535的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
代码如下:
服务器端:
package com.xiawenquan.serversocket.demo;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 发送端:
* @author xiawenquan
*
*/
public class FileSenderServerce {
private static ServerSocket serverSocket = null;
public static void main(String[] args) {
new FileSenderServerce().startSend("F:\\FunshionMedia\\android手机服务器FtpDemo.txt",8080);
}
private void startSend(String filePath,int port) {
// TODO Auto-generated method stub
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
Socket socket = null;
try {
File file = new File(filePath);
serverSocket = new ServerSocket(port);
System.out.println("连接通道已经建立");
while(true){//可以连接多个客户端
socket = serverSocket.accept();
System.out.println("正式建立连接");
if(socket != null){
outputStream = new DataOutputStream(socket.getOutputStream());
// 将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,
// 具体可以参见Think In Java 4th里有现成的代码。
outputStream.writeUTF(file.getName());
System.out.println("发送文件名称 == " + file.getName());
outputStream.writeLong((long) file.length());
System.out.println("发送文件大小 == " + file.length());
outputStream.flush();//发送
//从本地读取要上传的文件
inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
int buffSize = 1024;
byte buff[] = new byte[buffSize];
while(true){
if(inputStream != null){
int zise = inputStream.read(buff);
if(zise == -1){
break;
}
outputStream.write(buff, 0, zise);//把读取的数据写到输出流中
}
}
outputStream.flush();//把输出流中的数据刷新出去
System.out.println("上传完成");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {// 关闭所有连接
try {
if(outputStream != null){
outputStream.close();
}
if(inputStream != null){
inputStream.close();
}
if(socket != null){
socket.close();
}
if(serverSocket != null){
serverSocket.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
接收端:
package com.xiawenquan.serversocket.demo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.Socket;
public class FlieAcceptClient {
public static void main(String[] args) {
//192.168.0.5本机的ip
new FlieAcceptClient().getFile("F:\\FunshionMedia\\aa\\", "192.168.0.5", 8080);
}
private void getFile(String savePath, String ip, int port){
DataInputStream inputStream = null;
DataOutputStream outputStream = null;
Socket socket = null;
try {
socket = new Socket(ip, port);
inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
int sizeBuff = 1024;
byte buff[] = new byte[sizeBuff];
int passedlen = 0;
// 获取文件名称
savePath += inputStream.readUTF();
File file = new File(savePath);
if(file.exists()){
System.out.println("文件已经存在");
file.delete();
}
//在本地创建一个文件
outputStream = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
// 获取文件长度
long len = inputStream.readLong();
System.out.println("文件的长度为:" + len + " KB");
System.out.println("开始接收文件!");
int readZise = -1;
// 获取文件
while(true){
if(inputStream != null){
readZise = inputStream.read(buff);
if(readZise == -1){
break;
}
passedlen += readZise;
System.out.println("文件接收了" + (passedlen * 100 / len) + "%");
outputStream.write(buff, 0, readZise);
outputStream.flush();
if(passedlen == len){
break;//当读到的字节大小和文件大小一样就说明已经读完了
}
}
}
System.out.println("接收完成,文件存为" + savePath);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
return;
}finally{
try {
if(inputStream != null){
inputStream.close();
}
if(outputStream != null){
outputStream.close();
}
if(socket != null){
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
工程如下: