您的位置:首页 > 理论基础 > 计算机网络

Java基础--网络编程之TCP

q549130180 2015-04-28 14:38 99 查看
凌风博客原创作品。转载请注明出处:

演示tcp传输
1.tcp分客户端和服务端

2.客户端对应的对象时Socket

服务端对应的对象时ServerSocket

客户端

通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机

因为tcp是面向连接的,所以在建立socket服务时

就要有服务端存在,并连接成功,形成通路后,在该通道进行数据的传输

需求:给服务端发送一个文本数据

步骤:

1.创建Socket服务,并指定要连接的主机和端口。

[java] view
plaincopy





import java.io.*;

import java.net.*;

class TcpClient

{

public static void main(String[] args) throws Exception

{

//创建客户端的socket服务,指定目的主机和端口

Socket s = new Socket("192.168.1.102",10003);

//为了发送数据,应该获取socket流中的输出流

OutputStream out = s.getOutputStream();

out.write("tcp ge men lai le ".getBytes());//将数据写入到输出流中

s.close();

}

}

需求:定义端点接收数据并打印在控制台上

服务端:

1.建立服务端的socket服务,ServerSocket();

并监听一个端口

2.获取连接过来的客户端对象

通过ServerSocket的 accept方法,没有连接就会等,所以这个方法是阻塞式的。

3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据

并打印在控制台

4.关闭服务端(可选操作)。

[java] view
plaincopy





class TcpServer

{

public static void main(String[] args) throws Exception

{

//建立服务端Socket服务,并监听一个端口

ServerSocket ss = new ServerSocket(10003);

//通过accept方法获取连接过来的客户端对象

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+".....connected");

//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

System.out.println(new String(buf,0,len));

s.close(); //关闭客户端

ss.close(); //关闭服务端

}

}

演示tcp的传输的客户端和服务端的互访。

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

客户端

1.建立socket服务,指定要连接主机和端口

2.获取socket流中的输出流,将数据写入到该流中,通过网络发送给服务端

3.获取socket流中的输入流,将服务端反馈的数据获取到,并打印

4.关闭客户端资源

[java] view
plaincopy





class TcpClient

{

public static void main(String[] args) throws Exception

{

Socket s = new Socket("192.168.1.102",10004);

OutputStream out = s.getOutputStream();

out.write("服务端,你好".getBytes());

//接收服务端反馈回来的数据

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

System.out.println(new String(buf,0,len));

s.close();

}

}

class TcpServer

{

public static void main(String[] args) throws Exception

{

ServerSocket ss = new ServerSocket(10004);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....connected");

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

System.out.println(new String(buf,0,len));

OutputStream out = s.getOutputStream();

//发送反馈数据给客户端

out.write("哥们收到,你也好".getBytes());

s.close();

s.close();

}

}

需求:建立一个文本转换服务器

客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端

而且客户端可以不断的进行文本转换,当客户端输入over时,转换接收

分析:

客户端

既然是操作设备上的数据,那么就可以使用IO技术,并按照io的操作规律来思考

源:键盘录入

目的:网络设备,网络输出流

而且操作的是文本数据,可以选择字符流

步骤:

1.建立服务

2.获取键盘录入

3.将数据发给服务端

4.获取服务端返回的大写数据

5.结束,管资源

都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲

[java] view
plaincopy





import java.io.*;

import java.net.*;

class TransClient

{

public static void main(String[] args) throws Exception

{

Socket s = new Socket("192.168.1.102",10005);

//定义读取键盘数据的流对象

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

//定义目的,将数据写入到socket输出流,发给服务端

//BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

//定义一个socket读取流,读取服务端返回的大写信息

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

String line = null;

while ((line=bufr.readLine())!=null)

{

if("over".equals(line))

break;

out.println(line);

//bufOut.write(line);

//bufOut.newLine();

//bufOut.flush();

String str = bufIn.readLine();

System.out.println("server:"+str);

}

bufr.close();

s.close();

}

}

/*

服务端:

源:socket读取流

目的:socket输出流

都是文本,装饰

*/

class TransServer

{

public static void main(String[] args) throws Exception

{

ServerSocket ss = new ServerSocket(10005);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....conneted");

//读取socket读取流中的数据

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

//目的,socket输出流,将大写数据写入到socket输出流,并发送给客户端,

//BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;

//客户端停下来之后服务端就停下来了,是因为客户端读到s.close();时,返回-1.当readLine()读到-1时也就停下里了。

while ((line=bufIn.readLine())!=null)//readLine判断一行结束的标记是回车符

{

System.out.println(line);

out.println(line.toUpperCase());

//bufOut.write(line.toUpperCase());

//bufOut.newLine();

//bufOut.flush();

}

s.close();

ss.close();

}

}

/*

该例子出现的问题。

现象:客户端和服务端都在莫名的等待

为什么呢?

因为客户端和服务端都有阻塞式方法,这些方法没有读到结束标记。那么就一直等

而导致两端都在等待

*/

上传文件

[java] view
plaincopy





import java.io.*;

import java.net.*;

class TextClient

{

public static void main(String[] args) throws Exception

{

Socket s = new Socket("192.168.1.102",10006);

BufferedReader bufr = new BufferedReader(new FileReader("TcpDemo_5.java"));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

//使用标记作为结束标记

//DataOutputStream dos = new DataOutputStream(s.getOutputStream());

//long time = System.currentTimeMillis();

//out.println(time);

//dos.writeLong(time);

String line = null;

while ((line=bufr.readLine())!=null)

{

out.println(line);

}

s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记-1

//dos.writeLong(time);

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

String str = bufIn.readLine();

System.out.println(str);

bufr.close();

s.close();

}

}

class TextServer

{

public static void main(String[] args) throws Exception

{

ServerSocket ss = new ServerSocket(10006);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....conneted");

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

PrintWriter out = new PrintWriter(new FileWriter("server.txt"),true);

String line = null;

while ((line=bufIn.readLine())!=null)

{

out.println(line);

}

PrintWriter pw = new PrintWriter(s.getOutputStream(),true);

pw.println("上传成功");

out.close();

s.close();

ss.close();

}

}

上传图片

客户端

1.服务端点

2.读取客户端已有的图片数据

3.通过socket输出流将数据发给服务端

4.读取服务端反馈信息

5.关闭

[java] view
plaincopy





import java.io.*;

import java.net.*;

class PicClient

{

public static void main(String[] args) throws Exception

{

if (args.length!=1)

{

System.out.println("请选择一个jpg格式的图片.");

return ;

}

File file = new File(args[0]);

if (!(file.exists() && file.isFile()))

{

System.out.println("该文件有问题,要么不存在要么不是文件");

return ;

}

if (!file.getName().endsWith(".jpg"))

{

System.out.println("图片格式错误,请重新选择");

return ;

}

if (file.length()>1024*1024*5)

{

System.out.println("文件过大");

return ;

}

Socket s = new Socket("192.168.1.102",10007);

FileInputStream fis = new FileInputStream(file);

OutputStream out = s.getOutputStream();

byte[] buf = new byte[1024];

int len = 0;

while ((len=fis.read(buf))!=-1)

{

out.write(buf,0,len);

}

//告诉服务端数据已写完

s.shutdownOutput();

//接收反馈信息

InputStream in = s.getInputStream();

byte[] bufIn = new byte[1024];

int num = in.read(bufIn);

System.out.println(new String(bufIn,0,num));

fis.close();

s.close();

}

}

服务端

这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程

这时B客户端连接,只有等待

因为服务端还没有处理完A客户端的请求,还没有循环回来执行下次accept方法,所以

暂时获取不到B客户端对象

那么为了可以让多个客户端同时并发访问服务端

那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就是可以同时处理多个客户端请求。

如何定义线程呢?

只要明确了每一个客户端要在服务端执行的代码即可,将该代码存入run方法中。

[java] view
plaincopy





class PicThread implements Runnable

{

private Socket s;

PicThread(Socket s)

{

this.s = s;

}

public void run()

{

String ip = s.getInetAddress().getHostAddress();

try

{

int count = 1;

System.out.println(ip+"....connected");

InputStream in = s.getInputStream();

//防止文件名重复使用IP(count),作为文件名

File file = new File(ip+"("+(count)+")"+".jpg");

while(file.exists())

file = new File(ip+"("+(count++)+")"+".jpg");

FileOutputStream fos = new FileOutputStream(file);

byte[] buf = new byte[1024];

int len = 0;

while ((len=in.read(buf))!=-1)

{

fos.write(buf,0,len);

}

OutputStream out = s.getOutputStream();

out.write("上传成功".getBytes());

fos.close();

s.close();

}

catch (Exception e)

{

throw new RuntimeException(ip+"上传失败");

}

}

}

class PicServer

{

public static void main(String[] args) throws Exception

{

ServerSocket ss = new ServerSocket(10007);

while (true)

{

Socket s = ss.accept();

//将获取到的方法传给PicThread中的run方法执行,以达到多用户同时上传

new Thread(new PicThread(s)).start();

}

//ss.close();

}

}

客户端通过键盘录入用户名。

服务端对这个用户名进行效验

如果该用户存在,在服务端显示xxx,已登录

并在客户端显示 xxx,欢迎观临

如果该用户不存在,在服务端显示xxx,尝试登陆

并在客户端显示 xxx,该用户不存在

最多就登陆三次

[java] view
plaincopy





import java.io.*;

import java.net.*;

class LoginClient

{

public static void main(String[] args) throws Exception

{

Socket s = new Socket("192.168.1.102",10008);

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

//将数据发给服务端的写入流

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

//读取服务端发过来的信息的读取流

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

for (int x = 0;x<3 ;x++ )

{

String line = bufr.readLine();//读取键盘录入

if(line==null)

break;

out.println(line);//将键盘数据写入到给服务端的写入流

String info = bufIn.readLine();//读取服务端发来的信息

System.out.println("info"+info);

if(info.contains("欢迎"))

break;

}

bufr.close();

s.close();

}

}

class UserThread implements Runnable

{

private Socket s;

UserThread(Socket s)

{

this.s = s;

}

public void run()

{

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....connected");

try

{

for (int x = 0;x<3 ;x++ )

{

//读取客户端传过来的姓名

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

String name = bufIn.readLine();

if(name==null)

break;

BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));

//获取写入流对象,负责反馈数据

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;

boolean flag = false;

while ((line=bufr.readLine())!=null)//读取文件中的用户进行比较

{

if (line.equals(name))

{

flag = true;

break;

}

}

if (flag)

{

System.out.println(name+",已登录");

out.println(name+",欢迎光临");

break;

}

else

{

System.out.println(name+",尝试登陆");

out.println(name+",用户名不存在");

}

}

s.close();

}

catch (Exception e)

{

throw new RuntimeException(ip+"效验失败");

}

}

}

class LoginServer

{

public static void main(String[] args) throws Exception

{

ServerSocket ss = new ServerSocket(10008);

while (true)

{

Socket s = ss.accept();

new Thread(new UserThread(s)).start();

}

}

}
标签: