TCP网络编程(TCP网络编程实训报告)
2018-04-23网络编程-概述-SOCKET-端口绑定-编码解码
计算机都遵守的网络通信协议叫做TCP/IP协议。
因为互联网协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称TCP/IP协议。是一组协议族。完成通信的规范。
四种分类法和其中分类法:
端口号:用来标记唯一一个进程(范围:0~65535)
为什么不用pid?——在一个操作系统上,pid绝对不相同,而且进程pid唯一,但在不同系统上,获取另一个系统的pid特别费劲;但是端口对应的程序是确定的,所以端口就是用来区分进程的
端口号只有整数,0~65535。能区分同一服务器所有进程
知名端口:大家都知道的默认的端口,比如百度,0~1023
动态端口:1024~65535之间
查看端口信息的命令:netstat - an
IP地址的作用:用来标记一台电脑在网络中的数字。
同一局域网中,IP地址不能相同
网络号用来分辨不同网络,主机号用来区分不同主机
ip地址:用来在网络中标记一台电脑的一串数字,比如192.168.1.1;在本地局域网上是惟一的。
什么是socket?
socket(简称 套接字 ) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的(能完成多个电脑进程间的通信)
例如我们每天浏览网页、QQ 聊天、收发 email 等等。
UDP快,不稳定
TCP慢,稳定
会变的端口号
说明:
每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程序,当重新运行时,如果没有确定到底用哪个,系统默认会随机分配
记住一点:这个网络程序在运行的过程中,这个就唯一标识这个程序,所以如果其他电脑上的网络程序如果想要向此程序发送数据,那么就需要向这个数字(即端口)标识的程序发送即可。
UDP绑定信息
一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定
绑定的意义是使其不变 。
*一个电脑可以有多个IP地址
*单工:收音机 半双工:对讲机 全双工:电话
UDP和TPC(网络)都是全双工,同一时间能发能收
一般,接收方都需要绑定,发送方不需要绑定
绑定示例:
总结
一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行次程序端口可能会发生变化
一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的
*解包:
关于tcpip 网络编程中客户端和服务器的双向通信
服务器端与客户端都使用监听,客户端要与服务端通讯的时候,客户端会向服务端发送相关请求,并监听。服务端一直在监听,当收到请求后会返回相关信息给客户端。跟打电话是一样的。
c#网络编程中tcpListener和tcpClient的用法
在本教程中,我会向你展示如何用C#建立一个线程中的TCP服务端。如果你用过windows的sockets编写程序,你就知道有多麻烦。感谢.net框架,使得网络编程变得更容易了。
我们将建立一个非常简单的的服务器接受客户端连接,并可以发送和接收数据。服务器为每一个连接客户端产生一个线程,从理论上讲,可以接受多个连接(虽在实践中,Windows对此是有限制)。
下面看代码:
using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace TCPServerTutorial
{
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
}
}
上面建立了一个基本的服务器类。我们定义了一个TcpListener变量(TcpListener封装了底层套接字通信工作),同时定义了一个线程用于监听客户端的连接。接下来我们定义了ThreadStart的委托函数:ListenForClients。
代码如下:
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
这个函数非常简单。首先,它启动TcpListener,然后循环接受连接。 AcceptTcpClient的调用将阻塞线程的执行,直到一个客户端连接,在这里,我们触发一个线程来处理与我们的新客户端的通信。我用了ParameterizedThreadStart委托,所以我可以传递AcceptTcpClient调用返回的TcpClient对象到新线程。
ParameterizedThreadStart使用函数HandleClientComm。这个函数负责从客户端读取数据。让我们看看它。
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
第一步将client类型转换为TcpClient类型,因为ParameterizedThreadStart委托只能接受基本对象类型。下一步,从TcpClient得到NetworkStream用来读取数据。之后,通过一个while循环从客户端读取数据。 read调用会一直处于阻塞状态,直到从客户端接收到数据。如果从客户端读取到零字节,那么说明客户端已断开。在该例子里,我只是一个字符串转换成字节数组,并将它输出到控制台。当然,你会做一些更复杂的工作。如果socket出现错误或客户端断开连接,你应该调用TcpClient对象的close函数关闭连接,释放它使用的任何资源。
上面就是创建一个服务器线程,接受连接,并从客户端读取数据所需做的所有的事情。当然,如果服务端不能发送数据,那么就没什么用了。下面,让我们看看如何将数据发送到我们的连接的一个客户端。
NetworkStream clientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Client!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
从AcceptTcpClient返回的TcpClient对象用来发送数据给客户端。因此需要在服务端保存这些对象。通常可以创建一个TcpClient对象的集合。发送数据是非常简单的,只需要得到client的NetworkStream对象,然后调用它的write方法就可以了。
TCP服务端已经完成了。比较难的部分是定义一个协议用来在客户端和服务端之间发送信息。应用层的协议通常对不同的应用都是不一样的。所以我不打算讲解更多,你只需要实现你自己的。
如果没有一个客户端连接到服务端,那么这个服务端还有存在的意思吗?本教程主要是讲服务端编程,但这里有一个简短的代码,说明了如何设置一个基本的TCP连接,并发送一段数据。
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
第一步工作是获取客户端到服务端的连接。使用TcpClient.Connect方法。它需要知道服务端的IPEndPoint,在这里,我将连接到本地主机,端口号3000。然后发送字符串"hello Server!"
注意:从客户端或服务器写并不总是等于一个在接收端读。例如,客户端向服务器发送10个字节,但服务器可能无法在第一次读取的时候得到所有10个字节。使用TCP,几乎保证最终得到所有10个字节,但它可能需要不止读取一次。所以当设计交互协议的时候要注意这一点。
在tcp网络编程中,如何保证数据接收端能正确地接收到发送端发来的全部数据,急,谢谢!
TCP好象对数据的发送是否被接受,是否发送到目的地,完整等都有支持了,不需要过多的考虑,如果要考虑,应该考虑接受到的校验码,CRC等,利用校验码检查接收到的数据是否校验正确就可以了
似乎UDP不管数据是否发送到,或者丢失等都不管
个人理解就这样,不专业,也有些模糊
unix网络编程与tcpip详解看哪个
看《UNIX网络编程》。TCP/IP详解不错,它共有三卷,依次阅读循序渐进比较合理,容易掌握,第一卷是基础,第二卷是实现,第三卷是事务。另外以windows为基础的网络编程方面的书籍也可以看看。UNIX网络编程(UNP),有两卷,讲原理和实现。都是UNIX/.LINUX关于网络最经典的书籍之一,细细研究绝对有好处。
LINUX网络编程TCP服务器?客户端?有乱码怎么解决?
解决办法:
1.在客户端n=read(socketfd,buff,1023);代码之前加上memset(buff,0,sizeof(buff));,这是保证收到较短数据(使用TCP你不能保证每次接收的数据和发送的数据时等长的),打印也是正确的;
2.将客户端buff[n+1]+='\0';修改为buff[n]='\0';,这是因为n是下标,已经是最后一个位置了;
3.将服务器端buff[n+1]+='\0';修改为buff[n]='\0';,这是因为n是下标,已经是最后一个位置了,而且和第2)一样,那个加号也要去掉,应该是笔误吧;
4.最大的问题,将服务器端write(connectfd,buff,1023);,你怎么能够保证收到1023个字符呢?也应该将while中条件移出作为WHILE中的一条语句,而且加上前面所述的memset语句,而将这里的write(connectfd,buff,1023);修改为write(connectfd,buff,strlen(buff))。
祝共同进步!