您的位置:首页 > 编程语言 > Java开发

Java专题 Socket编程之慕课网版本

2016-01-07 13:21 501 查看
Java网络编程是基于Socket的编程,我们可以从以下5个方面学习,Java网络编程。
1、网络基础知识
2、InetAddress
3、URL
4、基于TCP的Socket编程
5、基于UDP的Socket编程

第一章 网络基础知识
1、IP地址、协议,端口的概念
IP地址现在的标准是IPv4
端口的作用就是区别同一台主机上不同应用程序的数据
范围是0-65535 其中0-1023为系统所保留的,最好别用
一些常见的端口为:
http:80 ftp :21 telnet:23
2、TCP/IP协议的模型

第二章 InetAddress
1、用于标识网络上的硬件资源,也就是互联网协议(IP)地址。
2、具体有哪些方法和方法对应的作用可查API帮助文档

第三章  URL
1、统一资源定位符,格式如下:
http: // www.imooc.com?username=tom&password=123#test
http为协议,?后面表示参数,#后面表示锚点
2、具体用法可以查API,其中几个有用的如openStream等可以记一下,会用到。

第四章 基于TCP进行Socket编程
1、所要用到的API类为:
ServerSocket、Socket

2、服务端对应的步骤为:
a、创建ServerSocket对象,并绑定相应的端口号。
b、通过ServerSocket对象的accept()方法对指定的端口进行Socket连接的监听。
c、获得指定的Socket连接对象
d、通过连接对象获得输入流,对客户端的输入进行读取。
e、通过连接对象获取输出流,将自己要发送给客户端的信息通过输出流发送给客户端
f、关闭相应的资源。

3、客户端需要做的事为:
@1、创建Socket对象对指定的主机的端口进行连接
@2、通过获取输出流,将要发送给服务器的信息写入。
@3、通过获取输入流,获得服务器的反馈信息。
@4、关闭相应的资源

代码示例如下:
[align=left]案例背景:[/align]
[align=left] 实现一个类似与QQ的即时通讯工具,实现客户端与服务器端的即时通讯,由客户端发起对话,之后需要持续显示对方说话的内容来输入要输入的话。[/align]
在服务器端要首先读一下InputStream,看看客户端输入了什么,然后在决定输出什么,所以在循环外有一个独立的System.
out.println("Client"
+is.readLine());
[align=left] 然后在循环中再次读取。[/align]

public
class
TCPServer {

/**
[align=left] *服务器端[/align]
[align=left] */[/align]

public
static
void
main(String[] args) {

[align=left] try{[/align]
ServerSocket server=
null;

try{
server=
new
ServerSocket(8000); //创建serverSocket对象,对指定端口进行监听

}
catch(Exception e){
System.
out.println("Server
cannot start normally!"
);
[align=left] }[/align]
Socket socket=
null;

try{

[align=left] socket=server.accept();//通过serverSocket实例获得Socket对象,完成连接,此方法为阻塞方法[/align]

}
catch(Exception e){
System.
out.println(e);
[align=left] }[/align]

[align=left] String line;[/align]
BufferedReader is=
new
BufferedReader(new
InputStreamReader(socket.getInputStream()));//获取输入流,读客户端发送的数据
PrintWriter os=
new
PrintWriter(socket.getOutputStream());//获取输出流,用来发送自己的数据

BufferedReader sin=
new
BufferedReader(new
InputStreamReader(System.in
));
System.
out.println("Client"
+is.readLine());
[align=left] line=sin.readLine();[/align]

while(!line.equals("exit"
)){

[align=left] os.println(line);[/align]
[align=left] os.flush();//注意这里的顺序,因为顺序必须为读一次写一次那样,在此服务器端,先读客户的,上面的is.readLine()完了之后进行输入,然后将输入结果回馈给用户,这样用户得消息后会在输入,这样我们在下面的is.readLine()的内容就是下一次用户的输入了,一定要注意这个顺序。如果只输入一次,然后读两次,第二次就会一直读不到,程序阻塞。[/align]

System.
out.println("Server:"
+line);
System.
out.println("Client"
+is.readLine());
[align=left] line=sin.readLine();[/align]
[align=left] }[/align]
[align=left] os.close();[/align]
[align=left] is.close();[/align]
[align=left] socket.close();[/align]
[align=left] server.close();[/align]
[align=left] [/align]
}
catch(Exception e){
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left]}[/align]

[align=left]}[/align]
[align=left] [/align]
public
class
TCPClient {

/**
*
客户端
[align=left] */[/align]

public
static
void
main(String[] args) {

try
{
Socket socket=
new
Socket("192.168.2.145"
,8000);
BufferedReader sin=
new
BufferedReader(new
InputStreamReader(System.in
));
PrintWriter os=
new
PrintWriter(socket.getOutputStream());
BufferedReader is=
new
BufferedReader(new
InputStreamReader(socket.getInputStream()));
[align=left] String readLine;[/align]
[align=left] readLine=sin.readLine();[/align]

while(!readLine.equals("exit"
)){
[align=left] os.println(readLine);//由客户端开始,发送数据给服务器。[/align]
[align=left] os.flush();[/align]
System.
out.println("Client:"
+readLine);
System.
out.println("Server:"
+is.readLine());
[align=left] readLine=sin.readLine();[/align]
[align=left] }[/align]
[align=left] os.close();[/align]
[align=left] is.close();[/align]
[align=left] socket.close();[/align]
}
catch
(UnknownHostException e) {
[align=left] e.printStackTrace();[/align]
}
catch
(IOException e) {
[align=left] e.printStackTrace();[/align]
[align=left] } [/align]
[align=left] }[/align]

[align=left]}[/align]

4、总结:在这里一定要理解输入输出流的意思,输入流和输出流的不同在于他们的作用不同,一个用来输入数据,一个用来输出数据,但是他们操作的是同一个文件,就比如说,就像在Socket中,InputStream中的数据是由OutputStream来输入的,他俩的内容是一样的,而且,输入一次才可以输出一次,比如你Writer了一次,现在可以Reader一次,如果read两次,第二次并不会执行,因为没有东西可以read,只能进行再次的write才能进行read。

那么现在我来写一个自己的QQ程序:跟上面差不多。
客户端:
public
class
TCPClient {

[align=left] /*[/align]
[align=left] * Socket 网络通信客户端[/align]
[align=left] */[/align]
[align=left] [/align]
public
static
void main(String[] args)
throws
UnknownHostException, IOException {
[align=left] [/align]
Socket socket =
new
Socket("127.0.0.1"
,8888);
BufferedReader sysin=
new
BufferedReader(new
InputStreamReader(System.in
));
PrintWriter os=
new
PrintWriter(socket.getOutputStream());
[align=left] [/align]
BufferedReader is=
new
BufferedReader(new
InputStreamReader(socket.getInputStream()));
[align=left] [/align]
[align=left] String line;[/align]

while(!(line=sysin.readLine()).equals("exit"
)){
[align=left] os.println(line);[/align]
[align=left] os.flush();[/align]
System.
out.println("I am Client, what I say is:"+line);
System.
out.println("I am Client , what Server say is :"+is.readLine());
[align=left] [/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] os.close();[/align]
[align=left] is.close();[/align]
[align=left] socket.close();[/align]

[align=left]}[/align]
[align=left]}[/align]
服务器端:

public
class
TCPServer {

/**
[align=left] * Socket网络通信服务器端[/align]
[align=left] */[/align]

public
static
void main(String[] args) {
[align=left] [/align]

try{
ServerSocket server=
null;

try{
[align=left] [/align]
server=
new
ServerSocket(8888);
[align=left] [/align]
}
catch(Exception e){
System.
out.println("Server cannot start normally!"
);
[align=left] }[/align]
Socket socket=
null;

try{
System.
out.println("************服务器已经启动****************"
);
[align=left] socket=server.accept();[/align]
[align=left] [/align]
}
catch(Exception e){
System.
out.println(e);
[align=left] }[/align]
[align=left] [/align]
BufferedReader sysin=
new
BufferedReader(new
InputStreamReader(System.in
));
BufferedReader is=
new
BufferedReader(new
InputStreamReader(socket.getInputStream()));
PrintWriter os=
new
PrintWriter(socket.getOutputStream());
System.
out.println("I am Server,Client says:"
+ is.readLine());
[align=left] String line=sysin.readLine();[/align]
[align=left] [/align]

while(!(line.equals("exit"
))){
System.
out.println("I am Server,I am saying :"+line);
[align=left] os.println(line);[/align]
[align=left] os.flush();//在这里就要注意顺序了。先把自己的数据发了再去获取下一次的。[/align]
System.
out.println("I am Server,Client says:"
+ is.readLine());
[align=left] [/align]
[align=left] line=sysin.readLine();[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] os.close();[/align]
[align=left] is.close();[/align]
[align=left] socket.close();[/align]
[align=left] server.close();[/align]
[align=left] [/align]
}
catch(Exception e){
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]}[/align]

5、基于多线程的Socket编程
在实际的网络通信中,通常是一个服务器要为很多台客户机提供服务,
在这种情况下就要对来自不同IP地址的连接进行分别的处理,首先想到的肯定是线程,因为线程是独立运行,在run()方法中可以对需要独立执行的代码进行执行。
此时就要建立一个Socket连接处理的线程类,每获得一个Socket连接,就要实例化一个该类。
public
class
ServerThread extends
Thread {
[align=left] // 和本线程相关的Socket[/align]
Socket
socket =
null;

public
ServerThread(Socket socket) {

this.socket
= socket;
[align=left] }[/align]
[align=left] //线程执行的操作,响应客户端的请求[/align]
public
void
run(){
InputStream is=
null;
InputStreamReader isr=
null;
BufferedReader br=
null;
OutputStream os=
null;
PrintWriter pw=
null;

try {

//获取输入流,并读取客户端信息
is =
socket.getInputStream();
isr =
new InputStreamReader(is);
br =
new BufferedReader(isr);
String info=
null;

while((info=br.readLine())!=null){//循环读取客户端的信息
System.
out.println("我是服务器,客户端说:"
+info);
[align=left] }[/align]

socket.shutdownInput();
//关闭输入流

//获取输出流,响应客户端的请求
os =
socket.getOutputStream();
pw =
new PrintWriter(os);
pw.write(
"欢迎您!"
);
pw.flush();
//调用flush()方法将缓冲输出
}
catch (IOException e) {
[align=left] e.printStackTrace();[/align]
}
finally{

//关闭资源

try {

if(pw!=null
)
[align=left] pw.close();[/align]

if(os!=null
)
[align=left] os.close();[/align]

if(br!=null
)
[align=left] br.close();[/align]

if(isr!=null
)
[align=left] isr.close();[/align]

if(is!=null
)
[align=left] is.close();[/align]

if(socket
!=null)

socket.close();
}
catch (IOException
e
) {
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left]}[/align]

然后再监听的服务端可以这么写:
public
class
Server {
public
static
void main(String[] args) {

try {

//1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket=
new
ServerSocket(8888);
Socket socket=
null;

//记录客户端的数量

int count=0;
System.out.println(
"***服务器即将启动,等待客户端的连接***"
);

//循环监听等待客户端的连接

while(true
){

//调用accept()方法开始监听,等待客户端的连接
[align=left] socket=serverSocket.accept();[/align]

//创建一个新的线程
ServerThread serverThread=new
ServerThread(socket);

//启动线程
[align=left] serverThread.start();[/align]
[align=left] [/align]
count++;
//统计客户端的数量
System.out.println(
"客户端的数量:"
+count);
[align=left] InetAddress address=socket.getInetAddress();[/align]
System.out.println(
"当前客户端的IP:"
+address.getHostAddress());
[align=left] }[/align]
}
catch (IOException e) {
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] }[/align]

客户端就不用变了。

第五章 基于UDP的编程
1、所要用的核心API有:
DatagramSocket、DatagramPacket

2、服务器端的过程如下:
@1、创建DatagramSocket,指定端口号
@2、创建DatagramPacket制定用来存放接受数据的位置
@3、接受数据
@4、读取接受的数据

3、客户端的过程如下:
@1、定义各种信息,InetAddress,port以及所要发送的数据
@2、创建DatagramPacket,用来生成发送的数据包
@3、创建DatagramSocket,用来发送数据
@4、发送数据

代码如下:
[align=left]/*[/align]
[align=left] * 服务器端,实现基于UDP的用户登陆[/align]
[align=left] */[/align]
public
class
UDPServer {
public
static
void main(String[] args)
throws
IOException {

/*
[align=left] * 接收客户端发送的数据[/align]
[align=left] */[/align]

//1.创建服务器端DatagramSocket,指定端口
DatagramSocket socket=
new
DatagramSocket(8800);

//2.创建数据报,用于接收客户端发送的数据

byte[] data =new
byte[1024];//创建字节数组,指定接收的数据包的大小
DatagramPacket packet=
new
DatagramPacket(data, data.length);

//3.接收客户端发送的数据
System.
out.println("****服务器端已经启动,等待客户端发送数据"
);
socket.receive(packet);
//此方法在接收到数据报之前会一直阻塞

//4.读取数据
String info=
new
String(data, 0, packet.getLength());
System.
out.println("我是服务器,客户端说:"
+info);
[align=left] [/align]

/*
[align=left] * 向客户端响应数据[/align]
[align=left] */[/align]

//1.定义客户端的地址、端口号、数据
[align=left] InetAddress address=packet.getAddress();[/align]

int port=packet.getPort();

byte[] data2="欢迎您!"
.getBytes();

//2.创建数据报,包含响应的数据信息
DatagramPacket packet2=
new
DatagramPacket(data2, data2.length, address, port);

//3.响应客户端
[align=left] socket.send(packet2);[/align]

//4.关闭资源
[align=left] socket.close();[/align]
[align=left] }[/align]
[align=left]}[/align]

[align=left]/*[/align]
[align=left] * 客户端[/align]
[align=left] */[/align]
public
class
UDPClient {
public
static
void main(String[] args)
throws
IOException {

/*
[align=left] * 向服务器端发送数据[/align]
[align=left] */[/align]

//1.定义服务器的地址、端口号、数据
[align=left] InetAddress address=InetAddress.getByName("localhost");[/align]

int port=8800;

byte[] data="用户名:admin;密码:123"
.getBytes();

//2.创建数据报,包含发送的数据信息
DatagramPacket packet=
new
DatagramPacket(data, data.length, address, port);

//3.创建DatagramSocket对象
DatagramSocket socket=
new
DatagramSocket();

//4.向服务器端发送数据报
[align=left] socket.send(packet);[/align]
[align=left] [/align]

/*
[align=left] * 接收服务器端响应的数据[/align]
[align=left] */[/align]

//1.创建数据报,用于接收服务器端响应的数据

byte[] data2=new
byte[1024];
DatagramPacket packet2=
new
DatagramPacket(data2, data2.length);

//2.接收服务器响应的数据
[align=left] socket.receive(packet2);[/align]

//3.读取数据
String reply=
new
String(data2, 0, packet2.getLength());
System.
out.println("我是客户端,服务器说:"
+reply);

//4.关闭资源
[align=left] socket.close();[/align]
[align=left] }[/align]
[align=left]}[/align]

总结:

重点:
Socket通信原理
基于TCP的Socket编程
经验与技巧:
多线程中要设置线程的优先级,否则会很慢,因为系统的线程居多,不定什么时候运行呢
是否关闭输入输出流,有时候关闭输入输出流会导致Socket也关闭了,这不是我们想要的
我们进行传输的时候,用的都是字符串的示例,但是实际生活中,更多的是传对象或者文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: