tcp服务器编程
㈠ TCP和UDP网络通讯的区别及实现方式是什么
TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,在 OSI模型中,它完成第四层传输层所指定的功能。x0dx0aUDP:是User Datagram Protocol的简称,用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。x0dx0aTCP和UDP传输就类似于我们的手机通电话和手机发短信,一种必需连通了,才能够通话,相对来说比穗肢较可靠,传输速度比较快,另一种可以在关机状态(无连接)发送信息,相对来说,可靠性比较差,传输速度较慢。具体的差别如下:x0dx0aTCP协议面向连接,UDP协议面向非连接 x0dx0a TCP协议传输速度慢,UDP协议传输速度快 x0dx0a TCP协议保证数据顺序,UDP协议不保证 x0dx0a TCP协议保证数据正确性,UDP协议可能丢包 x0dx0a TCP协议对系统资源要求多,UDP协议要求少x0dx0a不管是基于TCP还是基于UDP的网络通讯编程,都要区分服务器端和客户端,下面以TCP为例,实现客户端和服务器端通讯的实现步骤:x0dx0aTCP服务器端的编写步骤:x0dx0a1. 首先,你需要创建一个用于通讯的套接口,一般使用socket调用来实现。这等睁族正于你有了一个用于通讯的电话:) x0dx0a 2. 然后,你需要给你的套接口设定端口,相当于,悉悔你有了电话号码。这一步 一般通过设置网络套接口地址和调用bind函数来实现。 x0dx0a 3. 调用listen函数使你的套接口成为一个监听套接字。 以上三个步骤是TCP服务器的常用步骤。 x0dx0a 4. 调用accept函数来启动你的套接字,这时你的程序就可以等待客户端的连接了。 x0dx0a 5. 处理客户端的连接请求。 x0dx0a 6. 终止连接。x0dx0aTCP编程的客户端一般步骤是:x0dx0a1、创建一个socket,用函数socket();x0dx0a 2、设置socket属性,用函数setsockopt();* 可选x0dx0a 3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选 x0dx0a 4、设置要连接的对方的IP地址和端口等属性;x0dx0a 5、连接服务器,用函数connect()(相当于拨号); x0dx0a 6、收发数据,用函数send()和recv(),或者read()和write()(相当于通话);
㈡ 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))。
祝共同进步!
㈢ TCP通讯服务器程序用什么语言写最好
C语言绝对是适合的配谨拿,只要你能写出来。C语言运行的效率高,不解释的。
java也勉强可以吧。能用培搭C语言写的话,java不做考虑晌做。
㈣ TCP服务器和客户机编程
真费时间呢…… import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;public class TcpServer {
public static void main(String[] args) {
try {
final int PORT = 8888;
ServerSocket serverSocket = new ServerSocket(PORT);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader in = new BufferedReader(isr); OutputStream os = socket.getOutputStream();
PrintWriter out = new PrintWriter(os,true); String line;
while((line = in.readLine()) != null) {
System.out.println("server got msg " + line + " from " + socket.getRemoteSocketAddress());
line = "I am server!";
out.println(line);
System.out.println("server sent size(byte): " + line.getBytes().length);
} out.close();
in.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
System.out.println(e);
System.exit(1);
}
}
}
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;public class TcpClient {
public static void main(String[] args) throws IOException {
try {
final String SERVER_ADDRESS = "127.0.0.1";
final int PORT = 8888;
Socket socket = new Socket(SERVER_ADDRESS,PORT); OutputStream os = socket.getOutputStream();
PrintWriter out = new PrintWriter(os,true); InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader in = new BufferedReader(isr); String line;
line = "A line sent by the client";
out.println(line); line = in.readLine();
System.out.println("client got: " + line); out.close();
in.close();
socket.close();
} catch (UnknownHostException e) {
System.out.println(e);
} catch (IOException e) {
System.out.println(e);
}
}
}
㈤ LINUX网络编程TCP的服务器 客户端 有乱码怎么解决
网一科技的代理服务器正规专业.我朋友推荐我用了效果很好。希望对你有帮助您好!今后一起共勉!更多交流在CSDN,365testing,测评网
㈥ 如何用C#实现多线程TCP协议的服务器端程序
用C#实现多线程TCP协议的服务器端程序:
// <summary>
//毁帆/ Tcp客户线程类(服务端),ThreadServerProcessor 线程产生的客户连接,用该线程读写
/// </summary>
public class ThreadClientProcessor
{
//Tcp连接实例
private TcpClient tcpClient;
//消息框,本来想写日志用
private System.Windows.Forms.ListBox MessageList;
private string Password; //该连接登陆密码
private string Cmd1Echo;
private string Cmd2Echo;
private bool ClientLogOn;//客户是否登陆
private bool TcpClose;
public ThreadClientProcessor(){}
//构造函数,参数解释:Tcp客户,消息框,该服务密码(password命令后的参数) ,命令回应串 1,2 ******************
public ThreadClientProcessor(TcpClient client , ListBox listBox,string LogonText ,string cmd1echo,string cmd2echo)
{
ClientList.Add(this); //把当前实例加入一个列表中,方便以后控制
this.tcpClient=client;
this.MessageList=listBox;
this.Password=LogonText;
this.Cmd1Echo=cmd1echo;
this.Cmd2Echo=cmd2echo;
this.ClientLogOn=false;
this.TcpClose=false;
}
public static char[] CmdSplit={' '}; //读来的串由' ' 进行分离,命名+' '+参数
//public const string[] Cmd=new string[] { "password","cmd1","cmd2","echo","bye"};
//该函数由你自己写,这个只是给一个例子,
//功能:命令处理器,给个命令串,返回该命令处理结果,把命令和处理结果放在一个文本文件里,便于系统升级
public string TcpCmd(string s)
{
string result;
try
{
string cmdarg=s.Trim();
string[] args=cmdarg.Split(CmdSplit);
string cmd=args[0].ToLower();
switch (cmd )
{
case "password" :
if (args.Length>1)
{
ClientLogOn= Password.Equals(args[1].Trim());
result=ClientLogOn? "登陆成功":"密码不正确,未登陆";
}
else result= "登陆时候,没有输入密码";
break;
case "cmd1":
result=ClientLogOn?this.Cmd1Echo:"该命令无权执行,请先登陆";
break;
case "cmd2":
result=ClientLogOn?this.Cmd2Echo:"该命令无权执行,请先登陆";
break;
case "echo":
result=string.Format("服务器回纤行雹应:\n {0}",s);
break;
case "bye":
this.TcpClose=true;
result="DisConnected";
break;
default:
result="不可识别的命令";
break;
}
}
catch
{
result="解析命令发生错误,你输入的是狗屁命令,TMD *^* ";
}
return result;
} //end cmd
//定带让义一个线程,该线程对应的函数是 void start()(不是Start())********************************
//一下程序主要是操作该线程
public System.Threading.Thread tcpClientThread;
//启动客户连接线程 *************************************************************
public void Start()
{
tcpClientThread=new Thread(new ThreadStart(start));
tcpClientThread.Priority=ThreadPriority.BelowNormal;
tcpClientThread.Start();
}
//断开该当前实例连接,终止线程 **************************************************************
public void Abort()
{
if (this.tcpClientThread!=null)
{
//tcpClientThread.Interrupt();
tcpClientThread.Abort();
//一定要等一会儿,以为后边tcpClient.Close()时候,会影响NetWorkStream的操作
Thread.Sleep(TimeSpan.FromMilliseconds(100));
tcpClient.Close();
}
}
//静态列表,包含了每个连接实例(在构造实例时候使用了 ArrayList.Add( object))
private static System.Collections.ArrayList ClientList=new ArrayList();
//断开所有的Tcp客户连接,静态方法*************************************************************
public static void AbortAllClient()
{
for(int j=0 ;j< ClientList.Count;j++)
{
//从实例列表中取一个对象,转化为ThreadClientProcessor对象
ThreadClientProcessor o=(ThreadClientProcessor ) ClientList[j];
//调用ThreadClientProcessor 对象的停止方法
o.Abort();
}
//清除连接列表
ClientList.Clear();
}
//读写连接的函数,用于线程//*******************************************************************
private void start()
{
byte[] buf=new byte[1024*1024]; //预先定义1MB的缓冲
int Len=0; //流的实际长度
NetworkStream networkStream=tcpClient.GetStream(); //建立读写Tcp的流
try
{
byte[] p=Encoding.UTF8.GetBytes(" 欢迎光临,请输入密码" );
//向Tcp连接写 欢迎消息
if (!this.ClientLogOn )
networkStream.Write(p,0,p.Length);
//开始循环读写tcp流
while (!TcpClose)
{
//如果当前线程是在其它状态,(等待挂起,等待终止.....)就结束该循环
if (Thread.CurrentThread.ThreadState!=ThreadState.Running)
break;
//判断Tcp流是否有可读的东西
if ( networkStream.DataAvailable)
{
//从流中读取缓冲字节数组
Len=networkStream.Read(buf,0,buf.Length);
//转化缓冲数组为串
string cmd=Encoding.UTF8.GetString(buf,0,Len);
this.MessageList.Items.Add("客户机:"+cmd);
//处理该缓冲的串(分析命令),分析结果为res串
string res=TcpCmd(cmd);
//把命令的返回结果res 转化为字节数组
byte[] result=Encoding.UTF8.GetBytes(res);
//发送结果缓冲数组给客户端
networkStream.Write(result,0,result.Length);
this.MessageList.Items.Add("服务器回应:"+res);
}
else
{
//Thread.Sleep(TimeSpan.FromMilliseconds(200d));
//this.MessageList.Items.Add("客户机无命令");
//如果当前Tcp连接空闲,客户端没有写入,则当前线程停止200毫秒
Thread.Sleep(TimeSpan.FromMilliseconds(200d));
}
}
㈦ 用C语言帮忙写一个“TCP Client/Server模式的通信程序设计与实现”
CLIENT:
#include <stdio.h>
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib,"Ws2_32")
#define PORT 6666 /* 客户机连接远程主机的端口 */
#define MAXDATASIZE 100 /* 每次可以接收的最大字节 */
int main()
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
char msg[MAXDATASIZE];
char *argv="127.0.0.1";
struct sockaddr_in their_addr; /* 对方的地址端口信息 */
WSADATA ws;WSAStartup(MAKEWORD(2,2),&ws); //初始化Windows Socket Dll
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
//如果侍基建立socket失败,退出程序
printf("socket error\n");
exit(1);
}
//连接对方
their_addr.sin_family = AF_INET; /* 协议类型是INET */
their_addr.sin_port = htons(PORT); /* 连接对方PORT端口悔洞 */
their_addr.sin_addr.s_addr = inet_addr(argv); /* 连接对方老前谨的IP */
if (connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1)
{
//如果连接失败,退出程序
printf("connet error\n");
closesocket(sockfd);
exit(1);
}
while(1){
scanf("%s",msg);
//发送数据
if (send(sockfd, msg, MAXDATASIZE, 0) == -1)
{
printf("send error");
closesocket(sockfd);
exit(1);
}
//接收数据,并打印出来
if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1)
{
//接收数据失败,退出程序
printf("recv error\n");
closesocket(sockfd);
exit(1);
}
buf[numbytes] = '\0';
printf("Received: %s\n",buf); }
closesocket(sockfd);
return 0;
}
SERVER:
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib,"Ws2_32")
#define MYPORT 6666 /*定义用户连接端口*/
#define BACKLOG 10 /*多少等待连接控制*/ #define MAXDATASIZE 100
int main()
{
int sockfd, new_fd; /*定义套接字*/
struct sockaddr_in my_addr; /*本地地址信息 */
struct sockaddr_in their_addr; /*连接者地址信息*/
int sin_size,numbytes; char msg[10],buf[MAXDATASIZE];
WSADATA ws;
WSAStartup(MAKEWORD(2,2),&ws); //初始化Windows Socket Dll
//建立socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
//如果建立socket失败,退出程序
printf("socket error\n");
exit(1);
}
//bind本机的MYPORT端口
my_addr.sin_family = AF_INET; /* 协议类型是INET */
my_addr.sin_port = htons(MYPORT); /* 绑定MYPORT端口*/
my_addr.sin_addr.s_addr = INADDR_ANY; /* 本机IP*/
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
{
//bind失败,退出程序
printf("bind error\n");
closesocket(sockfd);
exit(1);
}
//listen,监听端口
if (listen(sockfd, BACKLOG) == -1)
{
//listen失败,退出程序
printf("listen error\n");
closesocket(sockfd);
exit(1);
}
printf("listen...");
//等待客户端连接
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
printf("accept error\n");
closesocket(sockfd);
exit(1);
}
printf("\naccept!\n");
while(1) {
if((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) continue;
if(!strcmp(buf,"bye"))
{
//成功,关闭套接字
closesocket(sockfd);
closesocket(new_fd);
return 0;
}
printf("%s %d",buf,strlen(buf));
sprintf(msg,"%d",strlen(buf));
if (send(new_fd,msg,MAXDATASIZE, 0) == -1)
{
printf("send ERRO");
closesocket(sockfd);
closesocket(new_fd);
return 0;
}
}
}
㈧ Python网络编程 -- TCP/IP
首先放出一个 TCP/IP 的程序,这里是单线程服务器与客户端,在多线程一节会放上多线程的TCP/IP服务程序冲戚拍。
这里将服务端和客户端放到同一个程序当中,方便对比服务端与客户端的不同。
TCP/IP是因特网的通信协议,其参考OSI模型,也采用了分层的方式,对每一层制定了相应的标准。
网际协议(IP)是为全世界通过互联网连接的计算机赋予统一地址系统的机制,它使得数据包能够从互联网的一端发送至另一端,如 130.207.244.244,为了便于记忆,常用主机名代替IP地址,例如 .com。
UDP (User Datagram Protocol,用户数据报协议) 解决了上述第一个问题,通过端口号来实现了多路复用(用不同的端口区分不同的应用程序)但是使用UDP协议的网络程序需要自己处理丢包、重包和包的乱序问题。
TCP (Transmission Control Protocol,传输控制协议) 解决了上述两个问题,同样使用端口号实现了复用。
TCP 实现可靠连接的方法:
socket通信模型及 TCP 通信过程如下两张图。
[图片上传失败...(image-6d947d-1610703914730)]
[图片上传失败...(image-30b472-1610703914730)]
socket.getaddrinfo(host, port, family, socktype, proto, flags)
返回: [(family, socktype, proto, cannonname, sockaddr), ] 由元组组成的列表散羡。
family:表示socket使用的协议簇, AF_UNIX : 1, AF_INET: 2, AF_INET6 : 10。 0 表示不指定。
socktype: socket 的类型, SOCK_STREAM : 1, SOCK_DGRAM : 2, SOCK_RAW : 3
proto: 协议, 套接字所用的协议,如果不指定, 则为 0。 IPPROTO_TCP : 6, IPPRTOTO_UDP : 17
flags:标记,限制返回内容。 AI_ADDRCONFIG 把计算机无法连接的所有地址都过滤掉(如果一个机构既有IPv4,又有IPv6,而主机只有IPv4,则会把 IPv6过滤掉)
AI _V4MAPPED, 如果本机只有IPv6,服务却只有IPv4,这个标记会将 IPv4地址重新编码为可实际使用的IPv6地址。
AI_CANONNAME,返回规范主机名:cannonname。
getaddrinfo(None, 'smtp', 0, socket.SOCK_STREAM, 0, socket.AP_PASSIVE)
getaddrinfo('ftp.kernel.org', 'ftp', 0, 'socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG | socket.AI_V4MAPPED)
利用已经通信的套接字名提供给getaddrinfo
mysock = server_sock.accept()
addr, port = mysock.getpeername()
getaddrinfo(addr, port, mysock.family, mysock.type, mysock.proto, socket.AI_CANONNAME)
TCP 数据发送模式:
由于 TCP 是发送流式数据,并且会自动分割发送的数据包,而仔槐且在 recv 的时候会阻塞进程,直到接收到数据为止,因此会出现死锁现象,及通信双方都在等待接收数据导致无法响应,或者都在发送数据导致缓存区溢出。所以就有了封帧(framing)的问题,即如何分割消息,使得接收方能够识别消息的开始与结束。
关于封帧,需要考虑的问题是, 接收方何时最终停止调用recv才是安全的?整个消息或数据何时才能完整无缺的传达?何时才能将接收到的消息作为一个整体来解析或处理。
适用UDP的场景:
由于TCP每次连接与断开都需要有三次握手,若有大量连接,则会产生大量的开销,在客户端与服务器之间不存在长时间连接的情况下,适用UDP更为合适,尤其是客户端太多的时候。
第二种情况: 当丢包现象发生时,如果应用程序有比简单地重传数据聪明得多的方法的话,那么就不适用TCP了。例如,如果正在进行音频通话,如果有1s的数据由于丢包而丢失了,那么只是简单地不断重新发送这1s的数据直至其成功传达是无济于事的。反之,客户端应该从传达的数据包中任意选择一些组合成一段音频(为了解决这一问题,一个智能的音频协议会用前一段音频的高度压缩版本作为数据包的开始部分,同样将其后继音频压缩,作为数据包的结束部分),然后继续进行后续操作,就好像没有发生丢包一样。如果使用TCP,那么这是不可能的,因为TCP会固执地重传丢失的信息,即使这些信息早已过时无用也不例外。UDP数据报通常是互联网实时多媒体流的基础。
参考资料:
㈨ TCP编程和UDP编程的主要区别是什么
tcp和udp从协议上的主要区别是:tcp是可靠的,流时的,但是链接建立比较“重”,需要三次握手,udp不能保证数据一空知定到达接收方,并且数据包并友亏余不能保证按照发送方的顺序接收。编程上的区别应该并不大,因为底层的API都屏蔽了协好滚议上的差别。
㈩ 如何编程自己实现tcp/ip的三次握手
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:
未连接队列:在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。
Backlog参数:表示未连接队列的最大容纳数目。
SYN-ACK
重传次数
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。
半连接存活时间:是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。