網(wǎng)絡(luò)基礎(chǔ)知識(shí)
OSI分層:應(yīng)用層 表示層 會(huì)話層 傳輸層 網(wǎng)絡(luò)層 數(shù)據(jù)鏈路層 物理層
tcp/ip: 應(yīng)用層 傳輸層 網(wǎng)絡(luò)層 數(shù)據(jù)鏈路
ip地址:唯一標(biāo)識(shí)一臺(tái)主機(jī)
ipv4 32位 ipv6 128位 尋址 可以反映物理上的一個(gè)變化
MAC地址:48 固化在計(jì)算機(jī)中
ip地址又兩部分構(gòu)成:網(wǎng)絡(luò)號(hào)+主機(jī)號(hào)
端口號(hào):標(biāo)識(shí)一個(gè)應(yīng)用程序的代號(hào) 短整型
協(xié)議:共同遵守的約定 tcp協(xié)議 網(wǎng)絡(luò)中的規(guī)則
ip , http/https,/ftp, tcp/
ipv4頭部結(jié)構(gòu)
4位頭部長度:表示15行 每行4字節(jié)就是60字節(jié) 減去 基本的20字節(jié) 剩余的選項(xiàng) 40字節(jié)
TCP頭部結(jié)構(gòu)
剩余的選項(xiàng)仍然是 40字節(jié)
應(yīng)用程序傳遞數(shù)據(jù)的一個(gè)過程
tcp協(xié)議
這四層:應(yīng)用層 傳輸層 網(wǎng)絡(luò)層 數(shù)據(jù)鏈路
ip地址由網(wǎng)絡(luò)號(hào)和主機(jī)號(hào)共同構(gòu)成的
"129.168.1.1"點(diǎn)分十進(jìn)制轉(zhuǎn)化為
無符號(hào)整型:
unsignal int inet_addr();
無符號(hào)整型轉(zhuǎn)化為點(diǎn)分十進(jìn)制:
inet_ntoa();
每一個(gè)字節(jié)8位 都是十進(jìn)制轉(zhuǎn)化的,最后將四個(gè)字節(jié)組合在一起,變成一個(gè)無符號(hào)整型
大端:網(wǎng)絡(luò)字節(jié)序列 htons()
地址:ip+port
表示Ipv4的地址結(jié)構(gòu)
struct socketaddr_in ipv4;
通用的套接字地址
struct socketaddr;
套接字
像手機(jī)一樣進(jìn)行數(shù)據(jù)的收發(fā)
需要讓服務(wù)器先運(yùn)行起來,客戶端主動(dòng)連接服務(wù)器,所以服務(wù)器需要把自己的ip 和端口告訴客戶端
在Windows下查看ip地址
ipconfig
Linux下查看虛擬機(jī)ip地址
ifconfig
判斷兩個(gè)主機(jī)是否連通
ping
無法訪問目標(biāo)主機(jī) ,說明該網(wǎng)絡(luò)下沒有這個(gè)主機(jī)
請(qǐng)求超時(shí),可能有防火墻 沒有成功
網(wǎng)絡(luò)編程
tcp編程流程
圖示理解
tcp服務(wù)器 ,客戶端編程流程
bind和accept函數(shù)理解
bind就是看看saddr得ip地址端口有沒有問題,ip地址是不是寫錯(cuò)了,端口是不是被占用了,如果沒有問題,就將表示符合該地址綁定,取名成功
int c = accept(sockfd, (struct sockaddr *)&caddr, &len);
服務(wù)器會(huì)在該行阻塞,等待用戶端的連接,一旦connect成功,阻塞結(jié)束,得到新的描述符c,該c對(duì)應(yīng)剛才的客戶端,類似一個(gè)鏈接,每個(gè)c都對(duì)應(yīng)一個(gè)客戶端,表示一條鏈接。
監(jiān)視套接字和鏈接套接字理解
監(jiān)聽套接字 都是這一個(gè) 類似文件描述符 在一個(gè)進(jìn)程中,fd都是3 不變
鏈接套接字:一個(gè)鏈接 由于服務(wù)器012 被占用 監(jiān)視套接字是3 所以鏈接套接字從4開始,說明一個(gè)客戶端和服務(wù)器鏈接上了,如果另一個(gè)客戶端鏈接,那就是5 …
如果不理解,可以看這篇文章,講的挺通俗易懂的:
監(jiān)視套接字和鏈接套接字
int c = accept(sockfd,(struct sockaddr*) &caddr,&len);//阻塞
服務(wù)器剛開始是不知道客戶端的地址的,所以先 &caddr 把結(jié)構(gòu)體放這里,等客戶端根據(jù)服務(wù)器給的ip端口找到connect,此時(shí)accept接收,這個(gè)時(shí)候就知道了客戶端的地址和ip,存儲(chǔ)在caddr
為什么c變成了4 原來的sockfd是3 而客戶端的sockfd一直是3
類似用你的手機(jī)3給10086電話,你的電話號(hào)不變,一直是3 服務(wù)器類似一個(gè)服務(wù)中心,服務(wù)器剛開始也是10086 即3號(hào)手機(jī)接收,接聽到了一個(gè)用戶,就轉(zhuǎn)接到另一個(gè)人工客服接聽,即4 號(hào)手機(jī),原來的3號(hào)手機(jī)繼續(xù)接聽客戶的電話。一次類推。
linux和window下的編程實(shí)現(xiàn)
ser.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket (AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
exit(1);
}
struct sockaddr_in saddr, caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("192.168.1.49");//“127.0.0.1”
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if ( res == -1)
{
printf("bind err\n");
exit(1);
}
res = listen(sockfd,5);
if ( res == -1 )
{
exit(1);
}
while( 1 )
{
socklen_t len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*) &caddr,&len);//阻塞
if ( c < 0 )
{
continue;
}
printf("accept c=%d\n",c);
char buff[128] = {0};
int n = recv(c,buff,127,0);//阻塞
printf("buff=%s\n",buff);
send(c,"ok",2,0);
close(c);
}
}
cli.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if ( sockfd == -1)
{
exit(1);
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("192.168.1.49");
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if ( res == -1)
{
printf("connect err\n");
exit(1);
}
send(sockfd,"hello",5,0);
char buff[128] = {0};
recv(sockfd,buff,127,0);//ok
printf("buff=%s\n",buff);
close(sockfd);
}
Windows系統(tǒng)上的服務(wù)器和客戶端
//window servier
#if 0
//ConsoleApptcp.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <WinSock2.h> //網(wǎng)絡(luò)頭文件
#include <string.h>
#include <ws2tcpip.h> //socklen_t
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib") //網(wǎng)絡(luò)庫文件
//初始化網(wǎng)絡(luò)庫
void InitNetwork() {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return;
}
}
int main()
{
InitNetwork();
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET)
{
cout << "socket err" << endl;
return 0;
}
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
//saddr.sin_addr.S_un.S_addr = INADDR_ANY;
saddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.32");//這個(gè)要用需要加宏定義
//saddr.sin_addr.S_un.S_addr = inet_pton(AF_INET,"192.168.1.50",NULL);
int res = bind(sockfd, (SOCKADDR*)&saddr, sizeof(saddr));
if (res == SOCKET_ERROR)
{
cout << "bind err" << endl;
return 0;
}
if (listen(sockfd, 5) == SOCKET_ERROR)
{
cout << "listen err" << endl;
return 0;
}
while (true)
{
//struct sockaddr_in caddr;
SOCKADDR_IN caddr;
socklen_t len = sizeof(caddr);
int c = accept(sockfd, (SOCKADDR*)&caddr, &len);
if (c == INVALID_SOCKET)
{
continue;
}
cout << "accept c=" << c << endl;
char buff[128] = { 0 };
while (true)
{
if (recv(c, buff, 127, 0) <= 0)
{
break;
}
cout << buff << endl;
send(c, "ok", 2, 0);
}
closesocket(c);
}
}
#endif
//windows client
#if 0
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <WinSock2.h> //網(wǎng)絡(luò)頭文件
#include <string.h>
#include <ws2tcpip.h> //socklen_t
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib") //網(wǎng)絡(luò)庫文件
//初始化網(wǎng)絡(luò)庫
void InitNetwork() {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return;
}
}
int main()
{
InitNetwork();
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET)
{
cout << "socket err" << endl;
return 0;
}
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.49");
int res = connect(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
if (res == -1)
{
cout << "connect err" << endl;
closesocket(sockfd);
WSACleanup();
}
while (true)
{
cout << "input" << endl;
char buff[128] = { 0 };
cin >> buff;
if (strncmp(buff, "end", 3) == 0)
{
break;
}
send(sockfd, buff, strlen(buff), 0);
memset(buff, 0, 128);
recv(sockfd, buff, 127, 0);
cout << buff << endl;
}
closesocket(sockfd);
WSACleanup();
return 0;
}
#endif
tcp特點(diǎn)
int n = recv(c,buff,1,0);
一次只收一個(gè)字符
當(dāng)發(fā)送速度快,會(huì)一起寫到緩沖區(qū),然后一起發(fā)送,數(shù)據(jù)太大,會(huì)拆開發(fā)送
套接字有發(fā)送緩沖區(qū)和接收緩沖區(qū)
netstat
應(yīng)答確認(rèn) 超時(shí)重傳
亂序重拍 去重
滑動(dòng)窗口控制
tcp特點(diǎn)
面向連接的 可靠的 流式服務(wù)
udp編程流程
圖示理解
udp特點(diǎn)
無連接 不可靠 數(shù)據(jù)報(bào)服務(wù)
雙方無連接:服務(wù)器關(guān)了,再起啟動(dòng),發(fā)送消息還是能收到,在建立一個(gè)客戶端,也可以發(fā)送信息。
udp發(fā)送數(shù)據(jù)時(shí),要保證數(shù)據(jù)收完,否則其他數(shù)據(jù)就丟了
嚴(yán)格的一對(duì)一,發(fā)幾次收幾次
一個(gè)端口可以被一個(gè)套接字綁定,可以綁定兩個(gè),是協(xié)議不同
tcp在應(yīng)用層面不丟數(shù)據(jù),底層會(huì)丟,網(wǎng)絡(luò)層,丟了重發(fā)就行,tcp自身保證其可靠性
tcp適合傳文件 丟一個(gè)字節(jié)都不行
udp適合視頻通話 丟包就是卡了
http編程流程
圖示+理解
應(yīng)用層 http 瀏覽器和服務(wù)器之間的通訊
傳輸層 tcp
兩次以上的請(qǐng)求復(fù)用了同一個(gè)tcp連接,就是長連接
http用80號(hào)端口
https用443號(hào)端口
小于1024的端口,需要管理員才能訪問
后面有\(zhòng)r\n結(jié)束
最后一行還有一個(gè)\r\n
content_length 不包含報(bào)頭
服務(wù)器收到瀏覽器的信息,放到buff數(shù)組里,服務(wù)器知道了瀏覽器想訪問的資源就是index.html,服務(wù)器需要做的是找到該資源,發(fā)給瀏覽器就行
瀏覽器會(huì)自己發(fā)起一個(gè)請(qǐng)求,去訪問圖標(biāo)
這是一組請(qǐng)求,可能會(huì)有多次請(qǐng)求,在一次點(diǎn)擊的過程中文章來源:http://www.zghlxwxcb.cn/news/detail-642793.html
編程實(shí)現(xiàn)-網(wǎng)站服務(wù)器
myhttp.c文章來源地址http://www.zghlxwxcb.cn/news/detail-642793.html
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include<fcntl.h>
#define PATH "/home/ittao/code/day17"
int socket_init();
char *get_filename(char buff[])
{
if(buff==NULL){
return NULL;
}
char *ptr=NULL;
char*s=strtok_r(buff," ",&ptr);
if(s==NULL){
return NULL;
}
printf("way:%s\n",s);
s=strtok_r(NULL," ",&ptr);
return s;
}
void *thread_fun(void *arg)
{
int c = (int)arg;
while (1)
{
char buff[4096] = {0};
int n = recv(c, buff, 4095, 0);
if(n<=0){
break;
}
printf("buff:%s\n", buff);
char*filename=get_filename(buff);
if(filename==NULL){
send(c,"http err:404",12,0);
break;
}
printf("filename:%s\n",filename);
char path[256]={PATH};
if(strcmp("/",filename)==0){
strcat(path,"/index.html");
}else{
strcat(path,filename);
}
int fd=open(path,O_RDONLY);
if(fd==-1){
send(c, "http err:404", 12, 0);
}
int filesize=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char http_head[256]={" my HTTP/1.1 200 OK\r\n"};
strcat(http_head,"Server:myhttp\r\n");
sprintf(http_head+strlen(http_head),"Content-Length:%d\r\n",filesize);
strcat(http_head,"\r\n");
send(c,http_head,strlen(http_head),0);
char data[1024];
int num=0;
while((num=read(fd,data,1024))>0){
send(c,data,num,0);
}
close(fd);
}
close(c);
printf("client close\n");
pthread_exit(NULL);
}
int accept_client(int sockfd)
{
struct sockaddr_in caddr;
int len = sizeof(caddr);
int c = accept(sockfd, (struct sockaddr *)&caddr, &len);
return c;
}
int main()
{
int sockfd = socket_init();
if (sockfd == -1)
{
exit(1);
}
while (1)
{
int c=accept_client(sockfd);
if (c != -1)
{
pthread_t id;
pthread_create(&id, NULL, thread_fun, (void *)c);
}
}
}
int socket_init()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
saddr.sin_addr.s_addr = inet_addr("192.168.1.49");
int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
if (res == -1)
{
printf("bind err\n");
return -1;
}
res = listen(sockfd, 5);
if (res == -1)
{
return -1;
}
return sockfd;
}
到了這里,關(guān)于網(wǎng)絡(luò)編程 tcp udp http編程流程 網(wǎng)絡(luò)基礎(chǔ)知識(shí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!