Socket編程 涵蓋代碼和函數參數介紹

  • Socket是針對端系統,也就是用戶主機上開發程序,不涉及網絡設備(交換機、路由器)
  • 獨立于網卡驅動層之上,不涉及硬件,即基于Packet Driver編程

  • 端:是指通信雙方兩臺電腦
  • ?應用編程接口API 也就是兩端 應用層內部的應用進程之間的? 數據通信,遵循應用層協議,他們之間數據通信需要底層(傳輸層、網絡層、數據鏈路層、物理層)的支持,底層一般是涉及到操作系統的知識
  • 應用進程 和 操作系統 之間需要一個接口,這個接口就是應用編程接口 API,這個接口API就是應用進程的控制權和操作系統的控制權之間進行轉換的一個系統調用的接口。即應用進程通過API接口將控制權交給操作系統,操作系統執行完成之后將執行結果返還給我們的應用進程

  • ?幾種典型的應用編程接口
    • UNIX環境下? 套接字接口? 簡稱套接字 socket
    • 微軟的 Windows Socket Interface 即 WINSOCK
  • Socket API
    • 適用于絕大多數操作系統
    • 實現了應用進程間通信的抽象機制
    • 面向多種協議棧接口 TCP /IP
    • Internet網絡應用最為典型的API接口
    • 通信模型:客戶/服務器 (C/S)架構

?問題:主機和客戶端都運行了多個應用進程,如何保證客戶端進程和與之對應的服務器應用進程正確匹配呢?

  • IP地址只能區分 主機
  • 考慮到 跨主機進程通信需要傳輸層的支持,使用端口號區分 不同進程之間的標識

  • ?服務器對外提供服務 需要提供 IP地址 + 端口號
  • 但是服務器內部使用套接字描述符來管理套接字,這個描述符本質就是一個結構體指針,結構體內部詳細記錄了字段對應的信息
  • Socket抽象,其操作類型對于文件的操作,將其看做一個特殊的文件
  • 返回的套接字描述符
    • 最為關鍵的是地址信息
    • 短點地址 = IP地址 + 端口號

  • ?使用套接字的時候需要指定本地和遠程的IP地址和端口號 ,就需要使用sockaddr_in設置端點地址,就包含了IP地址和端口號等信息
    • 地址族:一般使用AF_INET? 涉及到不同的協議棧

Socket?API函數 (WinSock)

  • 基于linux的socket進行擴充
  • 前面加入了WSA 表示這個版本的 套接字工具 采用動態鏈接庫的方式進行創建

WSAStartup

?WSACleanup

  • 不帶WSA的函數接口適用于 WIN或者Linux,帶上WSA的函數只能適用于win環境下
  • int WSACleanup(void);
  • 應用程序在完成對請求的Socket庫的使用,最后需要調用WSACleanup函數,從而解除和Socket庫的綁定,釋放Socket庫所占用的系統資源

socket

  • 創建套接字,銜接 應用層和傳輸層之間的數據通信

  • ?套接字的類型
    • 使用的是TCP類型? ?套接字的類型是SOCK_STREAM
    • 使用的是UDP類型? 套接字的類型是 SOCK_DGRAM
    • 跳過傳輸層,直接實現 應用層和網絡層之間的數據通信,使用SOCK_RAW,需要特殊的權限,linux操作的話需要具備root權限,win需要用戶具備管理員權限,其具備 上述兩種方式的獨特之處?
  • TCP 和 UDP的區別
    • TCP:可靠 (數據不會出錯、丟失、亂序等)、面向連接、字節流傳輸、點對點
    • UDP:不可靠、無連接、數據報傳輸

closesocket

  • win使用的是closesocket
  • linux使用的是close
  • int closesocket(SOCKET sd);
  • 關閉一個描述符為sd的套接字
  • 如果多個進程共享一個套接字的話,調用closesocket將套接字的引用計數減一,減少至0才會真正關閉
  • 一個進程中的多個線程對一個套接字的使用無計數
    • 即同一個進程中的一個線程使用closesocket關閉套接字,這個進程中的其余線程也不能訪問這個套接字
  • 返回數值
    • 0? : 成功
    • SOCKET_ERROR? :? 失敗

bind

  • socket創建的時候,內部的套接字描述符并沒有涵蓋地址信息,比如IP地址和端口號,需要使用bind進行綁定,設定套接字的本地斷點地址?
  • 參數
    • 套接字描述符:也就是使用socket創建的
    • 端點地址
      • 結構 sockaddr_in
    • 客戶程序不需要調用bind函數,因為操作系統會幫助用戶填充IP地址和端口號
    • 服務器需要使用這個函數指定IP地址和端口號
      • IP地址如何綁定呢?
        • 如果主機安置了不同的網卡,分別連接在不同的網段,造成了網段隔離
        • 所以需要使用地址通配符? INADDR_ANY

listen

  • int listen(sd,queuesize);
  • 置服務器端的流套接字處于被動監聽狀態
    • 僅僅服務端調用
    • 僅用于面向連接的流套接字
  • 設置了連接請求隊列的大小
  • 返回數值
    • 0 成功
    • SOCKET_ERROR:失敗

connect

  • connect (sd,saddr,saddrlen)
    • 客戶端套接字? sd
    • 特定計算機的特定端口? saddr
  • 只適用于客戶端,使用connect函數和服務器進行連接
  • 通信協議
    • TCP:建立TCP連接
      • connect返回成功,表示建立連接,可以成功通信
    • UDP:指定服務器的端點地址
      • connect返回成功,可不一定會成功通信

accept

  • newsock = accept(sd,caddr,caddrlen);
  • 服務端調用accept函數從處于監聽狀態的流套接字sd中的客戶連接請求隊列中取出排在最前面的一個客戶請求,并且創建一個新的套接字 銜接 來自客戶端的套接字,形成一個通道
  • 注意事項:
    • 僅用于TCP套接字
    • 僅用于服務器?
  • 創建新的套接字,使用新的套接字 和 客戶端 進行通信
    • 原因
      • TCP是面向連接的、可靠的、點對點的。
      • 也就是客戶端和服務端 通過一個Socket建立連接,然后創建新的socket負責 客戶端和服務端的應用進程之間的通信,出于高并發的思想采用上述設計
      • 要不 服務端只能為一個客戶端提供服務,就不能同時為其余客戶端的用戶進行服務
      • 主線程或主進程繼續監聽新的請求,子線程通過創建新的連接請求

send / send to?

  • send (sd,*buf,len,flags)
  • sendto(sd,*buf,len,flags,destaddr,addrlen)
  • send函數TCP套接字(客戶和服務器) 或調用了connnect函數的UDP客戶端套接字,適用于TCP,因為已經連接了,就不需要ip地址和端口號了
  • sendto函數適用于UDP服務器套接字 與? 沒有調用connect函數的UDP客戶端套接字

recv / recv from

  • recv(sd,*buffer,len,flags)
  • rtecvfrom(sd,*buf,len,flags,senderaddr,saddrlen)
  • recv 函數從TCP連接的另外一端接收數據,或者從調用了connect函數的UDP客戶端套接字接收服務器發來的數據
  • recvfrom 函數從UDP服務器套接字與未調用connnect函數的UDP的客戶端套接字接收對端數據

setsockopt 和 getsockopt? 使用不多?

小結

  • connect 如果是tcp的話是真正的連接,如果是UDP沒有連接,僅僅指定一個端口和地址

?網絡字節順序

  • 表示層 解決數據表示轉換功能
  • TCP/IP 定義了標準的用于協議頭中的二進制的整數表示:網絡字節順序
  • 某些Socket API函數的參數需要存儲為網絡字節順序 (IP地址和端口號等等)
  • 可以實現本地字節順序和網絡字節順序的轉換
    • htons:? ?將本地字節順序? 轉換為? 網絡字節順序 (16bits)
    • ntohs:? ?將網絡字節順序? 轉換為?本地字節順序 (16bits)
    • htonl :? ?將本地字節順序? 轉換為? 網絡字節順序 (32bits)
    • ntohl:? ? 將網絡字節順序? 轉換為?本地字節順序 (16bits)

解析服務器的IP地址

  • 客戶端使用域名、IP地址標識服務器,但是IP協議需要的是32位二進制的IP地址,因此需要將域名或IP地址轉換為32位IP地址
  • 函數
    • inet_addr() 實現點分十進制IP地址到32位IP地址的轉換
    • gethostbyname()實現域名到32位IP地址的轉換
      • 返回一個指向hostent結構體的指針?

解析服務器(熟知)端口號

  • 客戶端還可以使用 服務名 標識服務器端口
  • 需要將服務器名 轉換為 熟知的端口號
  • 函數
    • getservbyname()
      • 返回一個指向servent結構的指針?

?解析協議號

  • 客戶端可能使用協議名 如 TCP 指定協議
  • 需要將協議名轉換為協議號 如 6
  • 函數
    • getprotobyname()實現協議名到協議號的轉換
    • 返回一個指向結構protoent的指針

?TCP客戶端軟件

  • 確定服務器的IP地址和端口號
  • 創建套接字
  • 分配本地端點地址(IP地址和端口號)
  • 連接服務器(套接字)
  • 遵循應用層協議進行通信
  • 關閉釋放連接

UDP客戶端軟件

  • 確定服務器的IP地址和端口號
  • 創建套接字
  • 分配本地端點地址(IP地址和端口號)
  • 指定服務器端點地址 構造UDP數據包
  • 遵循應用層協議進行通信
  • 關閉釋放連接

客戶端軟件的實現 connectsock()

  • 設計一個connectsock過程封裝底層的代碼
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<winsock.h>#ifdef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif /*INADDR_NONE*/void errexit(const char *);
/*connectsock --> allocate & connect a socket using TCP or UDP
*///host      服務器端點地址
//service   服務名
//transport 傳輸層協議
SOCKET connectsock(const char * host,const char* service,const char * transport){struct hostent     *phe;  //pointer to host information entry      struct servent     *pse;  //pointer to service information entrystruct protoent    *ppe;  //pointer to protocal iunformation entrystruct sockaddr_in sin;   //an Internet endpoint addressint s,type;               //socket descriptor and socket typememset(&sin,0,sizeof(sin));sin.sin_family = AF_INET;//Map service name to port numberif(pse = getservbyname(service,transport)){sin.sin_port = pse.s_port;}else if((sin.sin_port = htons((u_short)atoi(service))) == 0){errexit("can't get \"%s\" service entry\n",service);}//Map host name to IP address,allowing for dotted decimal_pointif(phe = gethostbyname(host)){memcpy(&cin.sin_addr,phe->h_addr,phe->h_length);}else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE){errexit("can't get \"%s\" host entry\n",host);}//Map protocol name to protocal numberif(ppe = getprotobyname(transport) == 0){errexit("can't get \"%s\" protocal entry\n",transport);}//Use protocal to choose a socket typeif(strcmp(transport,"udp")==0){type = SOCK_DGRAM;}else{type = SOCK_STREAM;}//Allocate a sockets = socket(PF_INET,type,ppe->p_proto);if(s == INVALID_SOCKET){errexit("can't create socket:%d",GetLastError());}//Connect the socketif(connect(s,(struct sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR){errexit("can't connect to %s.%s: %d\n",host,service,GetLastError());}return s;
}
  • UDP客戶端 和 TCP客戶端
#include <winsock.h>
SOCKET connectsock(const char*,const char*,const char*);//connectUDP -> connect to a specified UDP service on a specified host
SOCKET connectUDP(const char*host,const char* service){return connectsock(host,service,"udp")
}#include <winsock.h>
SOCKET connectsock(const char*,const char*,const char*);//connectUDP -> connect to a specified UDP service on a specified host
SOCKET connectTCP(const char*host,const char* service){return connectsock(host,service,"tcp")
}
  • 異常處理
#include<stdarg.h>
#include<stdio.h>
#include<stdlib.h>
#include<winsock.h>//errexit -> print an error message and exitvoid errexit(const char* format){va_list args;va_start(args,format);vfprintf(stderr,format,args);va_end(args);WSACleanup();exit(1);
}

訪問DAYTIME服務的客戶端

  • 獲取日期和時間
  • 雙協議服務(TCP\UDP)
  • 端口號為 13
  • localhost 說明 服務端和客戶端都部署在同一臺機器上
  • daytime 說明這是一個請求時間的服務

TCP

  • 代碼采用循環接收信息的方式來接收,是因為tcp是一種流傳輸的協議,發送端發送的數據并不意味著接收端收到的數據一樣?,有可能數據切片

?UDP

?

?UDP使用數據報的方式,因此每次發送和接收的數據是完整的,因此不需要使用循環,只需要一次接收即可

?四種類型基本服務器

  • 循環無連接? UDP

    • 流程
      • 創建套接字
      • 綁定端點地址 INADDR_ANY + 端口號
      • 反復接收來自客戶端的請求
      • 遵循應用層協議,構造響應報文,發送給客戶
    • 數據發送
      • 服務器不可以使用connect()函數
      • 無連接服務器使用sendto()函數發送數據報
    • 數據接收
      • 使用recvfrom函數接收數據,自動提取
  • 循環面向連接? TCP

    • 創建(主)套接字? 并綁定端口號
    • 設置(主)套接字為被動監聽模式,準備用于服務器
    • 調用accept()函數接收下一個請求(通過主套接字),創建新的套接字用于和客戶端建立連接
    • 遵循應用層協議,反復接收客戶請求,通過新的套接字構造并發送響應報文,發送給客戶
    • 完成為特定的客戶端服務之后,關閉和客戶端之間的連接 返回步驟3
  • 并發無連接

    • 主線程 第一步?創建套接字? 并綁定端口號
    • 主線程 第二步? 反復調用recvfrom()函數 接收下一個客戶端的請求,并創建新線程 處理客戶響應
      • 子線程 第一步 接受特定的請求
      • 子線程 第二步 依據應用層的協議構造響應的報文? 并調用sendto()發送
      • 子線程 第三步 退出(子線程處理完成一個請求之后便會終止)
    • 注意事項:
      • 主線程仍然在調用 recvfrom函數,不斷的接收請求 創建線程響應服務
  • 并發面向連接
    • 主線程 第一步?創建(主)套接字? 并綁定端口號
    • 主線程 第二步?設置(主)套接字為被動監聽模式,準備用于服務器。
    • 主線程 第三部?反復調用accept()函數 創建主套接字,接收下一個客戶端的下一個連接請求,并創建新線程 處理客戶響應
      • 子線程 第一步 接受特定的請求
      • 子線程 第二步 依據應用層的協議與特定的用戶進行交互
      • 子線程 第三步 退出(子線程處理完成一個請求之后便會終止)(線程終止)

代碼

?

?無連接循環 DAYTIME服務器

?面向連接的并發的DAYTIME服務器

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446151.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446151.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446151.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springcloud阿里巴巴五大組件_如何無縫遷移 SpringCloud/Dubbo 應用到 Serverless 架構

簡介&#xff1a; 本文分為三部分來介紹&#xff0c;分別介紹微服務應用遷移到 SAE 的優勢&#xff0c;如何遷移 SpringCloud/Dubbo 應用到 SAE 上&#xff0c;以及針對 SpringCloud 應用遷移的實踐演示。背景通過前面幾節課程的學習&#xff0c;相信大家對于 SAE 平臺已經有了…

pythonnone用法_python中None返回值如何使用?

None是python中的特殊存在。作為函數&#xff0c;在用到返回值的經常使用。今天小編就來講講None作為函數返回值時&#xff0c;會出現的三種情況。 一、作為操作類函數的默認返回值 當某個操作類函數不需要任何返回值時&#xff0c;通常就會返回 None。同時&#xff0c;None 也…

C++ Byte轉十六進制字符串輸出

代碼 例子一 typedef std::vector<unsigned char> bytes; std::string BytesToStr(const bytes& in) {bytes::const_iterator from in.cbegin();bytes::const_iterator to in.cend();std::ostringstream oss;for (; from ! to; from)oss << std::hex <&…

frame中src怎么設置成一個變量_Go 語言設計哲學之七:變量聲明須一致

Go 語言&#xff0c;使用變量之前需要先進行變量的聲明。var s string “Golang"n : 666Go 語言有兩類變量包級別(package varible)&#xff1a;在 package 級別可見的變量。如果是導出變量&#xff0c;該變量也可以被視為全局變量&#xff1b;局部變量(local varible)&a…

數據填充規則之PKCS7

程序輸入的數據全部使用Hex 十六進制的格式 IV 00000000000000000000000000000000Source(加密數據) char input_date[] {a,a,a,a,.......} Ascll編碼 需要轉16進制input_data 303030303030303030303030303030CC CC表示此位無數據注意事項&#xff1a;考慮到程序采用 PKCS…

getdevicecaps在哪個頭文件里_一招定勝負,while (true) 和 for (;;) 到底哪個更快

在JDK8u的jdk項目下做個很粗略的搜索&#xff1a;mymbp:/Users/me/workspace/jdk8u/jdk/src$ egrep -nr "for (s?;s?;" . | wc -l 369mymbp:/Users/me/workspace/jdk8u/jdk/src$ egrep -nr "while (true" . | wc -l 323并沒有差多少。其次&#…

SM4 ECB加密模式 數據對比試驗論證

程序如下 開啟服務器密碼機&#xff0c;調用SM4加密函數&#xff0c;需要注意的是程序輸入的數據全部使用Hex 十六進制的格式 Key IV Data IV 00000000000000000000000000000000Source(加密數據) char input_date[] {a,a,a,a,.......} Ascll編碼 需要轉16進制input_data …

二分法查找c語言程序_C語言的那些經典程序 第十四期

戳“在看”一起來充電吧!C語言的那些經典程序 第十四期本期小C給大家帶來三個用C語言解決實際問題的典例。如果全都理解&#xff0c;相信肯定能給大家帶來收獲&#xff01;接下來讓我們看看是哪些程序吧&#xff01;1字符查找源程序&#xff1a;運行結果&#xff1a;程序分析:該…

C++ puts函數 打印字符串很方便

參考鏈接 c puts函數_在C / C 中使用puts&#xff08;&#xff09;函數_從零開始的教程世界-CSDN博客

centos網絡隔一段時間就斷_計算機網絡總結

POST跟GET的區別作用GET用于獲取資源&#xff0c;而POST用于傳輸實體參數GET的參數以字符串的格式出現在URL中&#xff0c;而POST的參數存儲在請求實體中。因為URL只支持ASCII碼&#xff0c;故GET的參數如果存在中文等字符就需要先進行編碼&#xff0c;POST參考支持標準字符集。…

C++/C++11中std::runtime_error的使用

參考鏈接 C/C11中std::runtime_error的使用_網絡資源是無限的-CSDN博客_runtimeerror

有python基礎學java_Python基礎學習篇

導讀Python是一種解釋型、面向對象、動態數據類型的高級程序設計語言。Python由Guido van Rossum于1989年底發明&#xff0c;第一個公開發行版發行于1991年。像Perl語言一樣, Python 源代碼同樣遵循 GPL(GNU General Public License)協議。一. 列表1.1 列表的介紹列表是python的…

使用wireshark抓包,本地環回測試通信數據已經通過SM4國密算法加密

具體操作 本實驗采用 本地環回測試開啟wireshark抓包工具&#xff0c;設定端口號 tcp.port 5099 &#xff08;5099為服務端對外開啟服務的端口號&#xff09;&#xff0c;不可以使用ip.addr指定ip地址&#xff0c;因為本地環回測試&#xff0c;相關信息太多&#xff0c;使用端…

public 函數_UE4精品教程 | 渲染編程(C++篇)【第三卷:從仿函數到std::function再到虛幻4Delegate】...

本文轉載于YivanLee知乎作者專題目錄鏈接&#xff1a;https://zhuanlan.zhihu.com/p/67694999這幾天研究了一下虛幻4的delegate&#xff0c;但是想要理解這個&#xff0c;還得從仿函數說起。下面是一段代碼例子&#xff1a;class MyFunctor{ public: int operator()(int …

C語言深度剖析書籍學習記錄 第一章 關鍵字

C語言標準定義了32個關鍵字 union聲明聯合數據類型 Union declaration - cppreference.com維護足夠的空間來置放多個數據成員中的“一種”&#xff0c;而不是為每一個數據成員配置空間&#xff0c;在 union 中所有的數據成員共用一個空間&#xff0c;同一時間只能儲存其中一個…

js頁面自適應屏幕大小_移動端自適應布局方法的calc()與vw

前端人員在處理移動端自適應布局時&#xff0c;目前前端最流行的方法應該就是使用媒體查詢&#xff0c;來設置HTML的字體大小&#xff0c;然后用rem為單位對Dom的寬高進行設置&#xff0c;這個方法的優勢在于兼容性方面很好&#xff0c;劣勢則在于當前市場上不同的機型太多&…

C語言深度剖析書籍學習記錄 第二章 符號

\ 連接符號&#xff0c;// \ 可以把下一行也注釋調編譯器 刪除注釋時&#xff0c;會使用空格進行替代

詳細描述三個適于瀑布模型的項目_IT項目管理筆記——方法選擇和軟件評估

一、管理需求為什么要管理需求&#xff1f;避免失敗&#xff0c;提高項目的成功率和需求管理所帶來的其他好處軟件生命周期中&#xff0c;一個錯誤發現得越晚&#xff0c;修復錯誤的費用越高許多錯誤是潛伏的&#xff0c;并且在錯誤產生后很長一段時間才被檢查出來在需求階段&a…

Socket通信 客戶端加密數據,傳遞數據密文到服務端,服務端解密密文 輸出明文

server // sdf_cpp_warpper.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。 // server端#ifndef UNICODE #define UNICODE #endif#define WIN32_LEAN_AND_MEAN#include <iostream> #include <string> #include <sstream> #include …