tcp/ip简单模型

#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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值