10.4学习记录

一、日常八股

1.键入网址到页面显示,中间发生了哪些内容?

二、Socket网络编程

在VS上复习下Socket网络编程

1.大体流程

首先做服务端,与在Linux上不同,如果要在VS上使用Socket进行网络通信,需要引入网络库如下:

#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")

     WSADATA wsaData;   //初始化Winsock库
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        std::cerr << "WSAStartup failed: " << result << std::endl;
        return 1;
    }

 初始化完成之后,就可以建立套接字了,由于在服务端,需要一个socket绑定服务端的端口,还需要一个socket来绑定客户端的端口,用来对客户端进行收发数据,所以定义两个:

int server_fd, new_socket;  //声明服务器socket和新的客户端Socket

此外,还需要定义一个结构体用来存储地址信息,和地址结构体大小等信息

struct sockaddr_in address;  //声明用于存储信息的结构体地址
int addrlen = sizeof(address);  //地址结构体大小
const int port = 8080;

2.建立socket:

socket参数(domain(协议域),type(套接字类型),protocol(协议))

server_fd = socket(AF_INET,SOCK_STREAM,0);
if (server_fd == 0) {
	std::cerr << "socket creation err?" << std::endl;
	return 1;
}

此外还有setsockopt()函数

setsockopt()函数用于设置一个套接字选项。通过这个函数,可以对套接字的各种属性进行配置,如设置套接字的接收缓冲区大小、启用地址重用、设置发送超时等。

 设置基本信息到结构体,然后进行绑定,是将本地的网络地址与套接字相绑定。

	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_family = AF_INET;
	address.sin_port = htons(port);

	//绑定 
	if (bind(server_fd,(struct sockaddr*)&address,addrlen)<0) {
		std::cerr << "bind err!!!" << std::endl;
		return 1;
	}
//监听
int szbuf=3;
if (listen(server_fd,szbuf)<0) {
	std::cerr << "listen err!!!" << std::endl;
	return 1;
}

 服务端设置循环监听客户端的链接:由此可见 我设置两个socket的目的在于一个用来绑定本机地址,另一个socket用来接收客户端的链接,并进行网络通信。

while (true) {
	new_socket = accept(server_fd,(struct sockaddr*)&address,&addrlen);//阻塞的 
	if (new_socket < 0) {
		std::cerr << "accept err!!!" << std::endl;
		continue;
	}
	char szbuf[1024] = { 0 };
	SSIZE_T bytes_read = recv(new_socket,szbuf,sizeof(szbuf),0);
	if (bytes_read > 0) {
		std::cout <<"Client say:" << szbuf << std::endl;
		const char* message = "Hello stupid peter";
		send(new_socket,message,strlen(message),0);
	}
}

accept函数 

accept函数主要用于服务器端,它从已完成连接队列(由listen函数创建的队列)中取出一个已完成的连接请求,创建一个新的套接字来与客户端进行通信,并返回这个新套接字的描述符。原有的监听套接字(用于监听客户端连接请求的套接字)继续用于监听新的连接请求。

send函数:(sockfd(套接字描述符),buf(数据缓冲区指针),len(数据长度),flags(标志位))

len表示要发送的数据长度,以字节为单位。对于字符串数据,如果只想发送字符串的一部分,可以指定该部分的长度。

3.listen()函数的第二个参数

代表全连接队列长度,即已完成队列未完成队列的总长度,这个数字表示同一时间可以同时等待处理的客户端连接请求数量。

4.listen和TCP三次握手的关系

当服务器调用listen后,他开始等待客户端的连接请求,当客户端发起连接请求时,会进行TCP的三次握手。

三次握手完成之后,会将该链接请求移到已完成的队列。

服务器可以通过accept函数来获取已完成连接队列中的客户端的连接。

 这样一个简单的DEMO就最好了,现在的功能就是客户端发一句,服务端发一句,二者直接相互通信,但是注意如果你发的字符有空格,那么send函数将会自动拆分成了两个包发送。

服务端:

#include<iostream>
#include<cstring>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
int main() {
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		std::cerr << "WSAStartup failed: " << result << std::endl;
		return 1;
	}
	int server_fd, new_socket;  //声明服务器socket和新的客户端Socket
	struct sockaddr_in address;  //声明用于存储信息的结构体地址
	int opt = 1;                //设置选项
	int addrlen = sizeof(address);  //地址结构体大小
	const int port = 8080;

	//建立socket
	server_fd = socket(AF_INET,SOCK_STREAM,0);
	if (server_fd == 0) {
		std::cerr << "socket creation err?" << std::endl;
		return 1;
	}
	//设置socket选项
	//setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//用于socket的行为
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_family = AF_INET;
	address.sin_port = htons(port);

	//绑定 
	if (bind(server_fd,(struct sockaddr*)&address,addrlen)<0) {
		std::cerr << "bind err!!!" << std::endl;
		return 1;
	}
	//监听
	int szbuf=3;
	if (listen(server_fd,szbuf)<0) {
		std::cerr << "listen err!!!" << std::endl;
		return 1;
	}
	std::cout << "server is listening on port:" << port << "..." << std::endl;
	new_socket = accept(server_fd,(struct sockaddr*)&address,&addrlen);//阻塞的 
		if (new_socket < 0) {
			std::cerr << "accept err!!!" << std::endl;
			return 1;
		}
	//循环监听客户端的连接
	while (true) {

		char szbuf[1024] = { 0 };
		SSIZE_T bytes_read = recv(new_socket,szbuf,sizeof(szbuf),0);
		if (bytes_read > 0) {
			std::cout <<"Client say:" << szbuf << std::endl;
			//const char* message = "Hello stupid peter";
			char message[1024] = { 0 };
			std::cin >> message;
			send(new_socket,message,strlen(message),0);
		}
	}
	closesocket(server_fd);
	closesocket(new_socket);
	WSACleanup();
	return 0;
}

客户端代码: 

#include<iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
int main() {
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		std::cerr << "WSAStartup failed: " << result << std::endl;
		return 1;
	}
	int sockClien;
	sockClien = socket(AF_INET,SOCK_STREAM,0);
	if (sockClien<0) {
		std::cerr << "socket creation err?" << std::endl;
		return 1;
	}
	struct sockaddr_in address;
	inet_pton(AF_INET, "127.0.0.1", &address.sin_addr);
	address.sin_family = AF_INET;
	address.sin_port = htons(8080);
	if (connect(sockClien, (struct sockaddr*)&address, sizeof(address))<0) {
		std::cerr << "connect creation err?" << std::endl;
		return 1;
	}
	while (true) {
		//std::string message = "hello gus you win";
		std::string message;
		std::cin >> message;
		if (send(sockClien,message.c_str(), message.size(), 0)<0) {
			std::cerr << "send creation err?" << std::endl;
			return 1;
		}
		char szbuf[1024] = { 0 };
		int bytes_read =  recv(sockClien,szbuf,sizeof(szbuf)-1,0);
		if (bytes_read > 0) {
			std::cout << "Server say:" << szbuf << std::endl;
		}
		else if(bytes_read==0) {
			std::cout << "连接关闭:" << szbuf << std::endl;
		}
	}
	closesocket(sockClien);
	WSACleanup();
	return 0;
}

 1985.找出数组第k个大的整数

给你一个字符串数组 nums 和一个整数 k 。nums 中的每个字符串都表示一个不含前导零的整数。 返回 nums 中表示第 k 大整数的字符串。 注意:重复的数字在统计时会视为不同元素考虑。例如,如果 nums 是 ["1","2","2"],那么 "2" 是最大的整数,"2" 是第二大的整数,"1" 是第三大的整数。

 核心在于比较函数,很巧妙,由于是字符串数组,如果在比较中字符串长度较大的一方肯定更大,如果相等的话,那么就按照字典序比较(s1 > s2),字典序中字符编码较大的字符串更大。

最后用到STL容器中的nth_element()函数,nums.begin()和nums.end()确定了要操作的范围是整个nums向量。而nums.begin()+k-1则确定了位置,经过nth_element()操作之后,这个位置的元素将被放置到它按照cmp规则排序后的最终位置。而cmp的规则是,在特定位置的元素要比左面的元素大,比右面的元素小。

class Solution {
public:
    bool static cmp(string s1,string s2){
        return s1.size()!=s2.size()?s1.size()>s2.size():s1>s2;
    }
    string kthLargestNumber(vector<string>& nums, int k) {
      nth_element(nums.begin(),nums.begin()+k-1,nums.end(),cmp);
      return nums[k-1];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值