一、C/S模型
建立完整的TCP网络服务
客户端不需要bind,服务端需要bind:
因为客户端寻找服务端,因此需要绑定一个IP,同一个主机上有多个端口,因此需要绑定一个端口来监听是否有客户端寻求连接
二、windows需要初始化winsock2库,才能运行
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<WinSock2.h>//windos.h和winsock2.h有宏定义冲突
//需要在添加对应的库ws2_32.lib
//与linux相比,windows需要启动winsock库
int main() {
WORD ver = MAKEWORD(2, 2);//创建版本号
WSADATA dat;
WSAStartup(ver, &dat);//启动socket网络
/* */
WSACleanup();//关闭socket网络
return 0;
}
三、建立服务端:
1)创建socket,
socket( _In_ int af, _In_ int type, _In_ int protocol );
af 是IP地址族,type套接口的类型,protocol使用的传输协议,windows返回的是一个socekt,linux返回的是int,此时socket可能是INVALID_SOCKET
2)bind一个端口bind( _In_ SOCKET s, _In_reads_bytes_(namelen) const struct sockaddr FAR * name, _In_ int namelen );
第一个参数是套接字,第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度
3)监听listen( _In_ SOCKET s, _In_ int backlog );
第一个参数为套接字,第二个为允许多少客户端访问
4)等待客户端连接accept( _In_ SOCKET s, _Out_writes_bytes_opt_(*addrlen) struct sockaddr FAR * addr, _Inout_opt_ int FAR * addrlen );
第一个参数为服务端套接字,第二个为客户端协议的地址,第三个为客户端协议地址的长度,会生成新的socket之后的通信使用该套接字
5)发送数据send(
In SOCKET s,
In_reads_bytes(len) const char FAR * buf,
In int len,
In int flags
);第一个为客户端的套接字,第二个为发送的数据(必须为const char类型),第三个发送的数据的长度,
6)关闭套接字closesocket( _In_ SOCKET s );
#define WIN32_LEAN_AND_MEAN
#include<Windows.h>
#include<WinSock2.h>
#include<iostream>
using std::cout;
using std::endl;
int main() {
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
//建立服务端
//1.创建套接字
SOCKET sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//IP地址类型,套接口类型,传输协议类型
//2.绑定一个port
sockaddr_in sin = {};//这是一个结构,其中端口和IP地址都需要是网络字节序
sin.sin_family = AF_INET;
sin.sin_port = htons(4567);//采用htons
sin.sin_addr.S_un.S_addr = INADDR_ANY;//绑定默认地址,采用inet_addr
if (bind(sock, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) //套接字,指向特定协议地址结构的指针,该地址结构的长度
cout << "ERROR,绑定端口失败" << endl;
else cout << "绑定成功" << endl;
//3.监听端口
if (listen(sock, 5) == SOCKET_ERROR) cout << "监听失败" << endl;//允许多少用户访问
else cout << "监听成功" << endl;
//4.等待客户端连接
sockaddr_in client = {};
int nAddrLen = sizeof(sockaddr_in);
char msg[] = "hello,client";
while (true) {
SOCKET cSock = accept(sock, (sockaddr*)(&client), &nAddrLen);//生成新的套接字
if (cSock == INVALID_SOCKET) cout << "套接字无效" << endl;
//5.向客户端发送数据
send(cSock, msg, strlen(msg) + 1, 0);
}
//6.关闭自身连接
closesocket(sock);
WSACleanup();
}
四、创建客户端
1)创建套接字
2)连接服务器connect( _In_ SOCKET s, _In_reads_bytes_(namelen) const struct sockaddr FAR * name, _In_ int namelen );
第一个为套接字,第二个为服务器的协议地址的指针,该地址结构的长度
3)接受服务器信息recv( _In_ SOCKET s, _Out_writes_bytes_to_(len, return) __out_data_source(NETWORK) char FAR * buf, _In_ int len, _In_ int flags );
第一个参数为客户端套接字,第二个参数为接受的数据缓冲区char*,第三个为该缓冲区的大小出现错误socket状态为SOCKET_ERROR
4)关闭套接字
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<Windows.h>
#include<winSock2.h>
#include<iostream>
using std::cout;
using std::endl;
int main() {
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
//1.创建套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) cout << "套接字建立失败" << endl;
else cout << "建立成功" << endl;
//2.连接服务器
SOCKADDR_IN sin = {};
sin.sin_family = AF_INET;
sin.sin_port = htons(4567);//要连接的服务器的端口号
sin.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");
if (connect(sock, (sockaddr*)&sin, sizeof(sockaddr)) == SOCKET_ERROR) cout << "连接失败" << endl;
else cout << "连接成功" << endl;
//3.接收服务器信息
char recvbuf[256] = {};
recv(sock, recvbuf, 256, 0);
cout << recvbuf <<"接收到"<<endl;
//4.关闭套接字
closesocket(sock);
system("pause");
WSACleanup();
}