网络编程中的TCP编程



前言



        计算机网络是指两台或更多的计算机组成的网络,在同一个网络中,任意两台计算机都可以直接通信,因为所有计算机都需要遵循同一种网络协议。


一、概述。


        互联网是网络的网络( internet ),即把很多计算机网 络连接起来,形成一个全球统一的互联网。对某个特定的计算机网络来说,它可能使用网络协议ABC,而另一个计算机网络可能使用网络协议XYZ。如果计算机网络 各自的通讯协议不统一, 就没法把不同的网络连接起来形成互联网。因此,为了把计 算机网络接入互联网,就必须使用TCP/IP 协议。TCP/IP协议泛指互联网协议,其中最重要的两个协议是TCP协议和IP协议。只有使用TCP/IP协议的计算机才能够联入互联网,使用其他网络协议(例如NetBI0S、AppleTalk协议等)是无法联入互联网的。


网络模型

         由于计算机网络从底层的传输到高层的软件设计十分复杂,要合理地设计计算机网络模型,必须采用分层模型,每一层负责处理自己的操作。网络模型是ISO组织定义的一一个计算机互联的标准模型,注意它只是一个定义,目的是为了简化网络各层的操作,提供标准接口便于实现和维护。这个模型从上到下依次是:

●应用层,提供应用程序之间的通信;

●表示层:处理数据格式,加解密等等;

●会话层:负责建立和维护会话;

●传输层:负责提供端到端的可靠传输;

●网络层:负责根据目标地址选择路由来传输数据;

●数据链路层和物理层:负责把数据进行分片并且真正通过物理网络传输,例如,无线网、光纤等。

常用协议

        IP协议是一个分组交换协议,它不保证可靠传输。而TCP协议是传输控制协议,它是面向连接的协议,支持可靠传输和双向通信。TCP协议是建立在IP协议之上的,简单地说,IP协议只负责发数据包,不保证顺序和正确性,而TCP协议负责控制数据包传输,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过接收、确认、超时、 重传这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。

        TCP协议也是应用最广泛的协议,许多高级协议都是建立在TCP协议之上的,例如HTTP、SMTP等。

二、TCP编程



1,什么是Socket?

        在开发网络应用程序的时候,会遇到Socket 这个概念。Socket 是-个抽象概念, 一个应用程序通过一个Socket 来建立一个远程连接,而Socket 内部通过TCP/IP协议把数据传输到网络。


        Socket、TCP 和部分IP的功能都是由操作系统提供的,不同的编程语言 只是提供了对操作系统调用的简单的封装。例如,Java 提供的几个Socket 相关 的类就封装了操作系统提供的接、口:1 ServerSocket 类、| Socket 类。

        为什么需要Socket进行网络通信?因为仅仅通过IP地址进行通信是不够 的,同一台计算机同一时间会运行多个网络应用程序,例如浏览器、QQ、 邮件客户 端等。当操作系统接收到一个数据包的时候,如果只有IP 地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出Socket接口,每个应用程序需要各自对 应到不同的Socket,数据包才能根据Socket 正确地发到对应的应用程序。

        一个Socket 就是由IP地址和端口号(范围是0~ 65535)组成,可以把Socke t简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个0 ~ 655 35之间的数字,其中,小于1024 的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。

●101.202.99.2:1201

●101.202.99.2:1304

●101.202.99.2:15000

        使用Socket 进行网络编程时,本质上就是两个进程之间的网络通信。其中一个 进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。
因此,当Socket 连接成功地在服务器端和客户端之间建立后:

●对服务器端来说,它的Socket是指定的IP地址和指定的端口号;

●对客户端来说,它的Socket是它所在计算机的IP地址和一一个由操作系统分配的随机端口号。

服务器端

        要使用Socket编程,我们首先要编写服务器端程序。Java 标准库提供了ServerSocket来实现对指定IP和指定端口的监听。Serversocket的典型实现代码如下:

package Cm1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class ChatServer {
	public static void main(String[] args) {
		Map<String, String> chatMap = new HashMap<String, String>() {
			{
				put("你好", "你好呀");
				put("hi", "hi~");
				put("hello", "哈喽");
				put("吃了吗", "没呢,你呢");
				put("孤勇者", "爱你孤身走暗巷");
				put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
				put("很高兴认识你", "我也是哦");
			}
		};

		try (ServerSocket server = new ServerSocket(2333)) {
			while (true) {
				Socket client = server.accept();
				String clientIp = client.getInetAddress().getHostAddress();

				try (BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
						BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));) {

					String question = reader.readLine();
					if (question != null) {
						System.out.println("[服务器]来自客户端" + clientIp + "的提问" + question);
						String answer = chatMap.get(question);
						answer = answer == null ? "我不知道你在说什么" : answer;

						writer.write(answer);

						writer.newLine();
					}

				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

客户端

package In;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

import java.util.Scanner;

public class chatClient {
	public static void main(String[] args) {	
		Scanner input =new Scanner(System.in);
		
		while(true) {
		try(Socket client=new Socket("192.168.220.1",2333);
				BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(
					client.getOutputStream()));
				BufferedReader reader=new BufferedReader(new InputStreamReader(
					client.getInputStream()));){
			String question=input.nextLine();
			
			if(question.equals("over")) {
				
				break;
			}
			
			writer.write(question);
			writer.flush();
			
			client.shutdownOutput();
			
			String answer=reader.readLine();
			System.out.println("[客户端]来自服务器的回答"+answer);
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	}
		System.out.println("Game over");
}

}

运行结果如下图:

客户端:

服务器端:



Socket流

        当Socket 连接创建成功后,无论是服务器端,还是客户端,我们都使用Socke t实例进行网络通信。因为TCP是- -种基于流的协议,因此,Java标准库使用InputStream和OutputStream来封装Socket的数据流,这样我们使用Socket的流,和普通I0流类似:

// 用于读取网络数据:
InputStream in = sock.getInputStream();

// 用于写入网络数据:
OutputStream out = sock.getOutputStream();



        写入网络数据时,必须要调用flush() 方法。如果不调用flush() ,我们很可能会发现,客户端和服务器都收不到数据,这并不是Java标准库的设计问题,而是我们以流的形式写入数据的时候,并不是一写入就立刻发送到网络,而是先写入内 存缓冲区,直到缓冲区满了以后,才会一次性真正发送到网络,这样设计的目的是为了提高传输效率。如果缓冲区的数据很少,而我们又想强制把这些数据发送到网络, 就必须调用flush() 强制把缓冲区数据发送出去。



总结

● 使用Java进行TCP编程时,要使用Socket模型;

●服务器端用ServerSocket 监听指定端口;

●客户端使用Socket( InetAddress, port) 连接服务器;

●服务器端用accept() 接收连接并返回Socket 实例; 

●双方通过Socket打开InputStream / outputStream 读写数据;

●服务器端通常使用多线程同时处理多个客户端连接,利用线程池可大幅提升效率;flush()方法用于强制输出缓冲区到网络。

  • 32
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值