#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <iostream>
#include <string>
using namespace std;
/*
https://docs.microsoft.com/en-us/previous-versions/aa921082(v%3dmsdn.10)
套接字Socket =(IP地址:端口号)
套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。
服务器端执行流程
调用socket函数,建立一个套接字,该套接字用于接下来的网络通信
调用bind函数,将该套接字绑定一个地址和端口号
调用listen函数,使用该套接字监听连接请求
调用accept函数,接受该套接字连接请求
客户端执行流程
调用socket函数,创建一个套接字
调用connect函数,使用该套接字与服务器进行连接
套接字的工作过程(服务器端)
首先,服务器应用程序通过socket系统调用创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,不能与其他进程共享。
其次,服务器进程使用bind系统调用个套接字命名。将该套接字绑定一个地址和端口号
接下来,服务器进程开始等待客户连接到这个命名套接字,调用listen创建一个等待队列,以使存放来自客户的进入连接。
最后,服务器通过accept系统调用来接受客户的连接。此时,会产生一个与原有的命名套接字不同的新套接字,它仅用于与这个特定的客户端,而命名套接字则被保留下来继续处理来自其他客户的连接。
套接字的工作工程(客户端)
调用socket创建一个未命名套接字,将服务器的命名套接字作为一个地址来调用connect与服务器建立连接。
一旦建立了连接,就可以像使用底层文件描述符那样来用套接字进行双向的数据通信。
*/
void test() {
cout << "*****************【服务器】************" << endl;
WORD wdVersion = MAKEWORD(2, 2); //WORD是short 2.1版本
WSADATA wdScokMsg;
int nRes = WSAStartup(wdVersion, &wdScokMsg);
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建一个socket
//绑定 bind() 将该套接字绑定一个地址和端口号
sockaddr_in si; //c语言用结构体必须加struct sockaddr_in
si.sin_family = AF_INET; //和socket()函数各种参数一样
si.sin_port = htons(12345); //端口号
//si.sin_addr.s_addr = inet_addr("127.0.0.1");
si.sin_addr.s_addr = inet_addr("192.168.1.106");//本机的ip
int bres = bind(socketServer, (const sockaddr*)&si, sizeof(si));
//侦听 listen()
int srr = listen(socketServer, SOMAXCONN); //侦听
fd_set allSockets; //装多个客户端
FD_ZERO(&allSockets); //清零操作
//添加一个元素
FD_SET(socketServer, &allSockets); //添加服务器套接字
while (1) {
fd_set tempSockets = allSockets;
//临时,接住allSockets,不改变原有allSockets
//fd_set里面没有含有指针,结构体可以直接复制,用等号
struct timeval st;
st.tv_sec = 3;
st.tv_usec = 0;
//int nres = select(0,&tempSockets,&tempSockets,&tempSockets,&st);
int nres = select(0, &tempSockets, NULL, NULL, &st);
//指向要检查其可读性的一组套接字的可选指针 处理之后allSocket中只包含有响应套接字
//处理recv和accept
if (0 == nres)
continue;
else if (nres > 0) {//有响应
for (int i = 0; i < tempSockets.fd_count; i++) {
//取出所有有响应的套接字
if (tempSockets.fd_array[i] == socketServer) {
//服务器的套接字 accept
SOCKET socketClient = accept(socketServer, NULL, NULL);
if (socketClient == INVALID_SOCKET) { //出错了
continue;
}
FD_SET(socketClient, &allSockets); //把客户端套接字装进去
printf("%d开始上线了!\n", socketClient);
char buf[1024] = { 0 };
_itoa(socketClient, buf, 10);
send(socketClient, buf, strlen(buf), 0);
}
else { //客户端套接字
char strbuf[1024] = { 0 };
int nrecv = recv(tempSockets.fd_array[i], strbuf, 1023,0);
if (nrecv == -1) {//客户端强制掉线
//出错了
WSAGetLastError();//得到错误码 10054
//从套接字集合中去掉该套接字,并且释放
printf("%d下线了!\n", tempSockets.fd_array[i]);
SOCKET stemp = tempSockets.fd_array[i]; //先接住
FD_CLR(tempSockets.fd_array[i],&allSockets);
closesocket(stemp);//释放掉
}
else if (nrecv > 0) {
//接收到了消息
printf("来自%d的消息: %s\n",tempSockets.fd_array[i],strbuf); //处理传递过来的信息
}
}
}
}
else { //发生了错误
}
}
删掉一个元素
//FD_CLR(socketServer, &clientSockets);
//closesocket(socketServer);
判断socketServer是否在其中,在非零,不在零
//FD_ISSET(socketServer, &clientSockets);
//关闭网络库
closesocket(socketServer);
//清理网络库
WSACleanup();
}
int main() {
test();
system("pause");
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <WinSock2.h>
#include <string>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void test() {
cout << "*****************【客户端】************" << endl;
WORD wdV = MAKEWORD(2, 2);
WSADATA wdD;
int rw = WSAStartup(wdV, &wdD);
if (0 != rw) {
cout << "0 != rw" << endl;
system("pause");
}
//服务器的socket
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == socketServer) {
cout << "INVALID_SOCKET == socketServer" << endl;
system("pause");
}
//连接服务器
struct sockaddr_in serverMsg;
serverMsg.sin_family = AF_INET;
serverMsg.sin_port = htons(12345);
serverMsg.sin_addr.s_addr = inet_addr("192.168.1.106");
int rc = connect(socketServer, (struct sockaddr*) & serverMsg, sizeof(serverMsg));
if (SOCKET_ERROR == rc) {
cout << "SOCKET_ERROR == rc" << endl;
system("pause");
}
char buf[1024] = { 0 };
recv(socketServer,buf, 1023,0);
int myid = atoi(buf);
cout << "本客户端的id: " << myid << endl;
while (1) {
char buf[1024] = { 0 };
//int rr = recv(socketServer, buf, 1023, 0);
//if (SOCKET_ERROR == rr) {
// cout << "error" << endl;
// system("pause");
//}
//cout << "来自服务器的消息: " << buf << endl;
scanf("%s", buf);
send(socketServer, buf, strlen(buf), 0);
}
closesocket(socketServer);
WSACleanup();
}
int main()
{
test();
return 0;
}