10、網絡基礎和SOCKET
1、TCP/IP協議概述
- TCP/IP是互聯網的基礎
- OSI參考模型與TCP/IP參考模型對應關係:
- TCP/IP 實際上是一個一起工作的通信家族,爲網際數據通信提供通路。爲討論方便可將
- TCP/IP 協議組大體上分爲三部分:
- 1.Internet 協議(IP)
- 2.傳輸控制協議(TCP)和用戶數據報文協議(UDP)
- 3.處於TCP 和UDP 之上的一組協議專門開發的應用程序。它們包括:TELNET,文件傳送協議(FTP),域名服務(DNS)和簡單的郵件傳送程序(SMTP)等許多協議。
2、傳輸層協議 - TCP(傳輸控制協議)
- 傳輸層協議。包括傳輸控制協議TCP和用戶數據報文協議UDP。
- 傳輸控制協議(TCP)。由於IP 提供非連接型傳遞服務,因此TCP應爲應用程序存取網絡創造了條件,使用可靠的面向連接的傳輸層服務。該協議爲建立網際上用戶進程之間的對話負責。此外,還確保兩個以上進程之間的可靠通信。它所提供的功能如下:
- 1.監聽輸入對話建立請求。
- 2.請求另一網絡站點對話。
- 3.可靠的發送和接收數據。
- 4.適度的關閉對話。
三次握手
- 1、初始化主機通過一個同步標誌置位的數據段發出會話請求。
- 2、接收主機通過發回具有以下項目的數據段表示回覆:同步標誌置位、即將發送的數據段的起始字節的順序號、應答並帶有將收到的下一個數據段的字節順序號。
- 3、請求主機再回送一個數據段,並帶有確認順序號和確認號。
3、傳輸層協議 - UDP(用戶數據報文協議)
- 用戶數據報文協議(UDP)。UDP 提供不可靠的非連接型傳輸層服務,它允許在源和目的地站點之間傳送數據,而不必在傳送數據之前建立對話。此外,該協議還不使用TCP使用的端對端差錯校驗。當使用UDP時,傳輸層功能全都發揮,而開銷卻比較低。它主要用於那些不要求TCP協議的非連接型的應用程序。例如,名字服務、網絡管理、視頻點播和網絡會議等。
4、應用層協議
- Telnet
- 文件傳送協議(FTP 和TFTP)
- 簡單的郵件傳送協議(SMTP)
- 域名服務(DNS)等協議。
5、網絡編程基礎
socket概述
- 爲了簡化開發通信程序的工作,由Berkely學校開發了一套網絡通信程序的API函數標準
- socket標準被擴展成window socket和unix socket
- linux中的網絡編程通過socket接口實現。Socket既是一種特殊的IO,它也是一種文件描述符。一個完整的Socket 都有一個相關描述{協議,本地地址,本地端口,遠程地址,遠程端口};每一個Socket 有一個本地的唯一Socket 號,由操作系統分配。
SOCKET分類
- 流式套接字(SOCK_STREAM)
- 流式的套接字可以提供可靠的、面向連接的通訊流。它使用了TCP協議。TCP 保證了數據傳輸的正確性和順序性。
- 數據報套接字(SOCK_DGRAM)
- 數據報套接字定義了一種無連接的服務,數據通過相互獨立的報文進行傳輸,是無序的,並且不保證可靠,無差錯。使用數據報協議UDP協議。
- 原始套接字
- 原始套接字允許對低層協議如IP或ICMP直接訪問,主要用於新的網絡協議實現的測試等。
套接字地址結構
struct sockaddr{
unsigned short sa_family; /* address族, AF_xxx */
char sa_data[14]; /* 14 bytes的協議地址 */
};
//sa_family 一般來說, IPV4使用“AF_INET”。
//sa_data 包含了一些遠程電腦的地址、端口和套接字的數目,它裏面的數據是雜溶在一起的。
sockaddr_in地址結構
struct sockaddr_in {
short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口號 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一樣大小)*/
};
字節序列轉換
- 因爲每一個機器內部對變量的字節存儲順序不同(有的系統是高位在前,底位在後,而有的系統是底位在前,高位在後 ),而網絡傳輸的數據大家是一定要統一順序的。所以對與內部字節表示順序和網絡字節順序不同的機器,就一定要對數據進行轉換。
字節轉換函數
-
htons()——“Host to Network Short”
主機字節順序轉換爲網絡字節順序(對無符號短型進行操作2bytes)
-
htonl()——“Host to Network Long”
主機字節順序轉換爲網絡字節順序(對無符號長型進行操作4bytes)
-
ntohs()——“Network to Host Short”
網絡字節順序轉換爲主機字節順序(對無符號短型進行操作2bytes)
-
ntohl()——“Network to Host Long ”
網絡字節順序轉換爲主機字節順序(對無符號長型進行操作4bytes)
地址格式轉換
- linux提供將點分格式的地址轉於長整型數之間的轉換函數。
- inet_addr()能夠把一個用數字和點表示IP 地址的字符串轉換成一個無符號長整型。
- inet_ntoa()
- inet_aton()
基本套接字調用
socket() bind() connect()
listen() accept() send()
recv() sendto() shutdown()
recvfrom() close() getsockopt()
setsockopt() getpeername()
getsockname() gethostbyname()
gethostbyaddr() getprotobyname()
fcntl()
基於流套接字的編程流程
6、socket示例
//server.cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define PORT 0x8888
int main(int argc,char *argv[])
{
int sfp,nfp;
static int number=0;
struct sockaddr_in s_add,c_add;
char buffer[1024]={0};
printf("Hello,welcome to my server!\n");
sfp=socket(AF_INET,SOCK_STREAM,0);
if(-1==sfp){
printf("socket fail!\n");
return -1;
}
printf("socket ok!\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=htonl(INADDR_ANY);
s_add.sin_port=htons(PORT);
if(-1==bind(sfp,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
printf("bind fail!\n");
return -1;
}
printf("bind ok!\n");
if(-1==listen(sfp,5)){
printf("listen fail!\n");
return -1;
}
printf("listen ok\n");
socklen_t addrlen = sizeof(struct sockaddr_in);
while(1){
nfp=accept(sfp,(struct sockaddr *)(&c_add),&addrlen);
if(-1==nfp){
printf("accept fail!\n");
return -1;
}
printf("accept ok!\nServer start get connect from %#x :%#x\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
number++;
int ret=fork();
if(ret>0){
break;
}
}
while(1){
memset(buffer,0,sizeof(buffer));
int len=read(nfp,buffer,sizeof(buffer));
if(len>0){
printf("client_%d:%s\n",number,buffer);
write(nfp,buffer,sizeof(buffer));
}
}
close(sfp);
return 0;
}
//client.cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 0x8888
int main(int argc,char *argv[])
{
int cfd;
int recbytes;
char buffer[1024]={0};
struct sockaddr_in s_add;
printf("Hello,welcome to client !\n");
cfd=socket(AF_INET,SOCK_STREAM,0);
if(-1==cfd){
printf("socket fail!\n");
return -1;
}
printf("socket ok!\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=inet_addr("127.0.0.1");
s_add.sin_port=htons(PORT);
printf("s_addr=%#x,port : %#x\n",s_add.sin_addr.s_addr,s_add.sin_port);
if(-1==connect(cfd,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
printf("connect fail!\n");
return -1;
}
printf("connect to server success!\n");
while(1){
memset(buffer,0,sizeof(buffer));
printf("please input:");
fgets(buffer,sizeof(buffer),stdin);
printf("\n");
write(cfd,buffer,sizeof(buffer));
memset(buffer,0,sizeof(buffer));
if(-1==(recbytes=read(cfd,buffer,1024))){
printf("read data fail!\n");
return -1;
}
if(recbytes>0){
printf("server:%s\n",buffer);
//buffer[recbytes]='\0';
//printf("%s\n",buffer);
}
}
getchar();
close(cfd);
return 0;
}