服务器端:Server
#include <iostream> using namespace std; #define WIN32_LEAN_AND_MEAN //#include <windows.h>其中包含winsock.h,与winsock2.h重定义 #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { //1.加载库 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { printf("WSAStartup failed with error: %d\n", err); return 1; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { printf("Could not find a usable version of Winsock.dll\n"); WSACleanup(); return 1; } else printf("The Winsock 2.2 dll was found okay\n"); //2.Socket SOCKET socklisten = socket(AF_INET ,SOCK_STREAM ,IPPROTO_TCP ); if(socklisten == INVALID_SOCKET) { WSACleanup(); return 1; } //3.bind SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = inet_addr("192.168.3.154");//INADDR_ANY任意IP addr.sin_port = htons(1234); if(SOCKET_ERROR == bind(socklisten,(sockaddr*)&addr , sizeof(addr))) { closesocket(socklisten);
WSACleanup(); return 1; } //4.listen if(SOCKET_ERROR == listen(socklisten ,10)) { closesocket(socklisten); WSACleanup(); return 1; } //5.accept SOCKET sockWaiter = accept(socklisten,0,0); if(INVALID_SOCKET == sockWaiter) { closesocket(socklisten); WSACleanup(); return 1; } //6.recv,send char str[1024] = {0}; int nlen; while(1) { nlen = recv(sockWaiter,str,sizeof(str),0); if(nlen > 0) { cout<<str<<endl; cin>>str; send(sockWaiter ,str,sizeof(str),0); } } //7. closesocket(sockWaiter); closesocket(socklisten); //8. WSACleanup(); system("pause"); return 0; }
客户端:Client#include <iostream>
using namespace std; #define WIN32_LEAN_AND_MEAN //#include <windows.h>其中包含winsock.h,与winsock2.h重定义 #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { printf("WSAStartup failed with error: %d\n", err); return 1; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { printf("Could not find a usable version of Winsock.dll\n"); WSACleanup(); return 1; } else printf("The Winsock 2.2 dll was found okay\n"); //2.Socket SOCKET sockConnect = socket(AF_INET ,SOCK_STREAM ,IPPROTO_TCP ); if(sockConnect == INVALID_SOCKET) { WSACleanup(); return 1; } //3.Connect SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = inet_addr("192.168.3.154"); addr.sin_port = htons(1234); if(SOCKET_ERROR == connect(sockConnect,(sockaddr*)&addr , sizeof(addr))) { closesocket(sockConnect); WSACleanup(); return 1; } //4.recv,send char str[1024] = {0}; int nlen; while(1) { cin>>str; nlen = send(sockConnect ,str,sizeof(str),0); if(nlen > 0) { nlen = recv(sockConnect,str,sizeof(str),0); if(nlen > 0) cout<<str<<endl; } } //5.关闭套接字 closesocket(sockConnect); //6.关闭库 WSACleanup(); system("pause");
return 0; }
一个服务器端怎样连接多个客户端?多线程。
服务器端的接收缓冲区小于客户端的发送缓冲区:数据流可任意拆分 缺点:出现粘包现象(发送过快,网络中卡住)
解决方法:长连接和短连接(各自建立socket)
设置包头,发送数据长度
SYN:请求连接
ASK:回复
PSH:推送数据
RST:重置连接
URG:紧急指针
FIN:断开连接
TCP的三次握手:
SYN置1就表示这是一个连接请求或连接接受报文。
规定SYN=1时不能携带数据,但要消耗一个序号
规定连接建立后所有发送的报文的ACK必须为1
为什么要三次握手?(两次确认)
TCP为全双工通信,要互相确认连接才可以传送数据。举一个例子,A发送了两次SYN连接请求,第一次发送的滞留在网络中,第二次发送的与B建立了连接,结束后断开了连接,这时,滞留在网络中的第一次发送的SYN连接请求到达了B,B回复了SYN和ACK,要是两次握手的情况下(即没有A的确认就确认了连接)这是B等待A发送数据,A没有发送过连接请求所以不会理会B。浪费了B的资源。
四次挥手:
为什么要有2MSL?
1.允许老的重复分节在网络中消失
2.保证正常结束
A发送的ACK没有发送到B,B超时重传一个FIN,A可以重新发送ACK,
为什么3次握手要4次挥手?
因为在连接时,Server收到SYN后返回的ASK和SYN一起发送。但是在断开连接时,收到FIN报文后不能立即关闭socket,所以先回复ASK.当Server端都报文发送完毕后仔发送FIN报文。所以需要4次挥手。