Socket
套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.
Socket 类的构造方法和普通方法
用Socket类实现客户端向服务器端发送消息
/**
* 网络编程:
* 在两台不同的计算机之间传递数据
*
* 客户端:Apps 浏览器 pc软件
* 服务器端:存储/处理数据
*
* URL:统一的资源定位
* http:www.baidu.com/search?code=android&type=1
* http/https: 传输协议 Tcp/IP
* www.baidu.com : 域名 表示一台网络中的电脑
* ipv4 ipv6地址:唯一标识一台网络中的计算机
* 32位: 4个部分每个8字节
*
* DNS服务器:域名解析
* 将www.baidu.com类型的域名解析为对应的ip地址
* search 对应的后台程序文件 php java jsp
* ? 表示运行这个程序需要传递的参数
* code=android code是服务器端规定的字段
* & 如果有多个参数使用&符号链接
*
* ip地址:唯一标识某一台电脑
* 端口号:唯一标识电脑上的某一个进程(程序)80
*
* 数据传输:TCP/IP协议
* TCP:面向链接的 安全的
* UDP:面向无链接的 不安全 但快
*
* 网络中的数据传输:Socket
* Socket:客户端
* ServerSocket:服务器端
* */
//模拟客户端
class Client {
public static void main(String[] args) throws IOException {
//1.创建用于通信的socket
// 指明和谁通信:ip地址 端口号
Socket socket = new Socket("ip",8989);
// 接收服务器端的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取服务器端发来的数据
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
// 客户端向服务器端发送数据
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("你好啊");
socket.shutdownOutput();
}
}
//模拟服务器端
class Server{
public static void main(String[] args) throws IOException {
//1.创建服务器端的serverocket
ServerSocket ss = new ServerSocket(8989);
//2.获取连接的客户端的socket
Socket clientSocket = ss.accept();
//3.向客户端发送数据
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("登录成功");
clientSocket.shutdownOutput();
//4.接收客户端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}
}
升级版:消息由终端手动输入:
/**
* 手动输入内容 发送
* Socket扮演的是客户端
* ServerSocket扮演的是服务器端
*
*/
class MyClient {
public static void main(String[] args){
//连接服务器端的socket
Socket socket = null;
try{
socket = new Socket("ip",8888);
//接收服务器端信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//从键盘输入数据 发送给服务器端
} catch (IOException e) {
System.out.println("网络出错 请重新登录");
} finally {
//关闭连接
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class MyServer {
public static void main(String[] args){
//创建ServerSocket
try (ServerSocket ss = new ServerSocket(8888)){
//监听客户端的连接
Socket socket = ss.accept();
//从终端接收数据
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
//获取向客户端输出数据的输出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
//发送给客户端
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现客户端向服务器端发送图片:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Meida {
}
class MeidaClient{
public static void main(String[] args) throws IOException {
//连接服务器 获取socket
Socket socket = new Socket("ip",8080);
//创建服务器端对应的输入流 用于接收服务器端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(br.readLine());
//向服务器端发送文件(图片)
//1.将文件写入到内存里
String path = "D:\\桌面\\pokerplaymind.png";
FileInputStream fis = new FileInputStream(path);
//2.创建字节流 outputStream
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1){
bos.write(buf,0,len);
}
socket.shutdownOutput();
}
}
class MediaServer{
public static void main(String[] args) throws IOException {
//创建服务器端的ServerSoket
ServerSocket ss = new ServerSocket(8080);
//监听客户端连接
//当有客户端来连接这个服务器 就可以得到对应的socket
//当没有客户端来连接 服务器一直在这里等待
Socket socket = ss.accept();
//创建客户端对应的输出流 用于向这个客户端发送数据
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("连接成功 可以发数据了!");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
String path = "D:\\Android learning\\java2\\821Day13\\src\\main\\java\\swu\\w1nfred\\a821day13\\1.png";
FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[1024];
int len;
while((len = bis.read(buf)) != -1){
fos.write(buf,0,len);
}
}
}
多线程实现单服务器多客户端传递数据:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Myclass {
}
/**
*
*
* */
class Server{
//保存每一个连接过来的Socket对象
public static ArrayList<Socket> sockets = new ArrayList<>();
public static void main(String[] args)throws IOException {
ServerSocket ss =new ServerSocket(8888);
//不停的等待客户端来连接
while(true) {
Socket socket = ss.accept();
//当有客户端连接过来 就保存
sockets.add(socket);
//开启一个线程 处理每个客户端的输入
new ServerThread(socket).start();
}
}
}
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br= new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while((line = br.readLine())!=null){
//群发消息
//遍历Server维护的数组
for (Socket s:Server.sockets) {
//向socket对应的客户端发送消息
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);
}
}
} catch (IOException e) {
System.out.println("网络错误 请重新登录");
System.exit(-1);
}finally {
//关闭输入输出流
//关闭对应的socket连接
try {
if(br != null){
br.close();}
if(socket !=null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
super.run();
}
}
class Client{
public static void main(String[] args)throws IOException {
Socket socket = new Socket("ip",8888);
//主线程处理终端输入 发送给服务器端
//用一个子线程处理服务器端数据
new Thread(new ClientThread(socket)).start();
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while((line = keyin.readLine())!=null){
ps.println(line);
}
}
}
/**
* 创建一个子线程处理客户端接收服务器端数据
*
* */
class ClientThread implements Runnable{
private Socket socket;
public ClientThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
//获取服务器端的输入流对象
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取数据
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("网络出错 请重新登录");
System.exit(-1);
}finally {
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket !=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
chaos