日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

TCP协议的服务器与客户端的程序设计(代码注释超详细)

發布時間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP协议的服务器与客户端的程序设计(代码注释超详细) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在上篇博客中講到了三次握手和四次揮手:

Linux網絡編程--TCP中的三次握手和四次揮手_神廚小福貴!的博客-CSDN博客服務器編程和客戶端編程的大致流程如下:三次握手是在客戶端中的connect中完成的,具體如下:那么上述說到的SYN ACK這些是什么東西呢?上述的截圖取自《Linux高性能服務器編程》電子版的截圖!+根據書中所提到的在客戶端對服務器端connect的時候,由客戶端對服務器端發出一個SYN的請求連接的報文,值為i是32位序列號,然后服務器收到客戶端SYN之后,會反饋給客戶端一個自身服務器端的SYN報文和確認號報文ACK,其中ACK的值為客戶端和服務器端的SYN序...https://blog.csdn.net/qq_45829112/article/details/122278769?spm=1001.2014.3001.5501

?這篇我們來說一下TCP協議下服務器端和客戶端的程序設計!

先來看下客戶端和服務器端的設計原理:

?過程如上,具體的就是客戶端和服務器創建socket創建套接字,bind將本地地址和套接字綁在一起,listen創建監聽隊列,客戶端通過connect三次握手與服務器連接,然后服務器accept接受客戶端的連接請求,客戶端向服務器send數據,服務器再對客戶端send響應數據。大致流程就這樣,下面面來看代碼演示:

服務器端:

1.創建socket套接字

int sockfd = socket(AF_INET,SOCK_STREAM,0);

int?socket(int domain,int type, int protocol) 返回值為非負描述符的話-----成功,返回值為-1的話--失敗

?socket參數詳解:取自《Linux高性能服務器編程》

咱們測試用的是IPV4的網絡,所以用的是AF_INET(書上寫的是PF_INET,在Windows中AF_INET和PF_INET是一樣的)

2.bind將套接字綁定到一個地址

int res = bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)

?bind函數的返回值:成功----返回0? ? ? ?失敗----返回-1

bind 參數詳解:sockfd為第一步socket創建套接字返回的描述符

????????const struct sockaddr *addr為指向一個struct sockaddr類型的結構體變量,此結構體成員用于設置要綁定的ip和端口

? ? ? ? addrlen為結構體大小

3.listen創建監聽隊列

int res = listen(sockfd,5);

listen參數詳解:

sockfd 為 創建套接字的返回描述符;

backlog為已完成連接隊列個數

4.accept在套接字已完成隊列中接收一個連接

int res = accept(sockfd,const struct sockaddr *addr,socklen_t addrlen);

accept參數的詳解:

?

參數:取自百度百科

5.recv和send

size_t recv(int sockfd,void* buf,size_t len,int flags);size_t send(int sockfd,const void* buf,size_t len,int flags);

??????參數詳解:
對于recv來說,sockfd為客戶端對應套接字,buf 為存放接收數據的地方,len為存放數據區的大小,flags一般置為0

對send來說:sockfd接收端的套接字描述符,要發送的消息,發送消息的大小,flags一般置為0

客戶端

客戶端只有一個connect在服務器端中沒有出現

connect參數詳解:

?sockfd是socket返回的描述符

那個saddr是服務器端的地址

len是服務器端的saddr大小

服務器端代碼演示

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);//創建套接字assert(sockfd != -1);struct sockaddr_in saddr,caddr; //sockaddr_in在頭文件#include<netinet/in.h>或#include <arpa/inet.h>中定義,saddr代表服務器端地址  caddr代表客戶端地址memset(&saddr,sizeof(saddr),0);//saddr其實有四項成員,最后一項用來占位的,必須搞為0,索性我們開始直接給全部置為0,后面再來綁定ip和端口saddr.sin_family = AF_INET;//地址族,TCP/ipv4協議族saddr.sin_port = htons(6000);//端口為小端序列,htons轉換為網絡字節序,也是大端字節序(一般使用都是5000以上,5000以內一般都是特定使用的,比如你辦了個手機卡,你能用110這個號碼嘛,博客園因為110有特殊意義,一個道理)saddr.sin_addr.s_addr = inet_addr("192.168.0.108");//自己本地的IP地址(ifconfig)//inet_addr將點分十進制轉換為午飯后整型int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//將sockfd和本地IP綁定//為什么要這個呢(struct sockaddr*)強轉呢,bind這個參數類型為struct sockaddr與sockaddr_in類型不一致,所以強轉assert(res != -1);res = listen(sockfd,5);//監聽隊列assert(res != -1);while(1){int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr*)&caddr,&len); //accept參數中第三個參數為結構體大小的一個指針,所以前面求lenif( c < 0 ){continue;}printf("accept caddr = %d , caddr.ip = %s , caddr.port = %d \n",c,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));char buff[128] = {0};int n = recv(c,buff,127,0);printf("recv:(%d) = %s",n,buff);send(c,"ok",2,0);close(c);}
}

客戶端代碼演示

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);assert(sockfd != -1);struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("192.168.0.108");int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//那個強轉的話,和服務器端呢個強轉是大同小異的assert (res != -1);char buff[128] = {0};printf("input: \n");fgets(buff,128,stdin);send(sockfd,buff,strlen(buff),0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff = %s  \n",buff);close(sockfd);exit(0);
}

這樣的話,簡單的服務器和客戶端的編程就完成了,下面來看運行結果:

?當然這次的編程代碼只能接受一個數據,想要接受多個數據,或者多線程共同訪問一個服務器的話,在這個基礎上改一下代碼即可,后面再出一篇文章來講這個東西!

這就是我對socket編程的理解,如有不到位的地方,歡迎各位指出,共同學習,共同進步!

“任何一個不曾起舞的日子,都是對未來的辜負!”

總結

以上是生活随笔為你收集整理的TCP协议的服务器与客户端的程序设计(代码注释超详细)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。