基于socket网络编程技术实现TCP和UDP的流程详解及实例
具體函數講解太多,根據程序自行分析。
可以參考這篇文章:
https://blog.csdn.net/qq_41687938/article/details/119102328?spm=1001.2014.3001.5501
https://blog.csdn.net/weixin_42193813/article/details/105666316
目錄
一、socket
1.1 socket概述
1.2 socket接口簡介
1.3 Linux系統使用socket過程
二、基于socket的TCP通信
2.1 基于socket技術的TCP通信流程
2.2 基于socket技術的TCP通信流程框圖
2.3 TCP socket編程實例
2.3.1 服務端(service.c)
2.3.2 客戶端(client.c)
三、基于socket的UDP通信
3.1? 基于socket技術的UDP通信流程框圖
3.2? 基于socket技術的UDP通信流程
3.2.1 服務器流程主要分為下述6個部分。
3.2.2 UDP協議的客戶端流程
3.3 UDPSocket客戶服務器通信實例
3.3.1 服務端(service.c)
3.3.2 客戶端(client.c)
3.4 UDP編程注意:
一、socket
1.1 socket概述
socket是在應用層和傳輸層之間的一個抽象層,它把TCP/IP層復雜的操作抽象為幾個簡單的接口供應用層調用已實現進程在網絡中通信。
socket起源于UNIX,在Unix一切皆文件哲學的思想下,socket是一種"打開—讀/寫—關閉"模式的實現,服務器和客戶端各自維護一個"文件",在建立連接打開后,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。
1.2 socket接口簡介
socket():創建socket
bind():綁定socket到本地地址和端口,通常由服務端調用
listen():TCP專用,開啟監聽模式
accept():TCP專用,服務器等待客戶端連接,一般是阻塞態
connect():TCP專用,客戶端主動連接服務器
send():TCP專用,發送數據
recv():TCP專用,接收數據
sendto():UDP專用,發送數據到指定的IP地址和端口
recvfrom():UDP專用,接收數據,返回數據遠端的IP地址和端口
close():關閉socket
1.3 Linux系統使用socket過程
在Linux下進行程序運行的方法:(假設已經編寫好服務端程序(service.c),和客戶端程序(client.c))
(需要開啟兩個終端)
1. 先分別對兩個文件進行編譯(分別執行以下兩條命令)
gcc service.c -o service gcc client.c -o client2. 然后先運行服務器端
./service3.? 再在另一個終端中運行客戶端
./client4. 執行完成!
二、基于socket的TCP通信
2.1 基于socket技術的TCP通信流程
服務端(被動連接,需創建自己的地址信息)
創建一個套接字 ———socket()
綁定IP地址、端口等信息到socket上——bind()
監聽套接字——listen()
等待客戶端的連接請求——accept()
發送、接收數據——send()和recv(),或者read()和write()
關閉網絡連接——close()
客戶端
創建一個套接字——socket()
連接服務器——connect()
接收、發送數據——send()和recv(),或者read()和write()
關閉網絡連接——close()
2.2 基于socket技術的TCP通信流程框圖
2.3 TCP socket編程實例
2.3.1 服務端(service.c)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main(){//創建套接字int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//將套接字和IP、端口綁定struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充serv_addr.sin_family = AF_INET; //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址serv_addr.sin_port = htons(1258); //端口bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//進入監聽狀態,等待用戶發起請求listen(serv_sock, 20);//接收客戶端請求struct sockaddr_in clnt_addr;socklen_t clnt_addr_size = sizeof(clnt_addr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//向客戶端發送數據char str[] = "Hello World!";write(clnt_sock, str, sizeof(str));//關閉套接字close(clnt_sock);close(serv_sock);return 0; }2.3.2 客戶端(client.c)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> int main(){//創建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);//向服務器(特定的IP和端口)發起請求struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充serv_addr.sin_family = AF_INET; //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址serv_addr.sin_port = htons(1258); //端口connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//讀取服務器傳回的數據char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf("Message form server: %s\n", buffer);//關閉套接字close(sock);return 0; }三、基于socket的UDP通信
3.1? 基于socket技術的UDP通信流程框圖
UDP協議的程序設計框架,客戶端和服務器之間的差別在于服務器必須使用bind()函數來綁定偵聽的本地UDP端口,而客戶端則可以不進行綁定,直接發送到服務器地址的某個端口地址??驁D如圖所示。
基于socket的UDP通信流程示意圖3.2? 基于socket技術的UDP通信流程
3.2.1 服務器流程主要分為下述6個部分。
(1)建立套接字文件描述符,使用函數socket(),生成套接字文件描述符。
(2)設置服務器IP地址和端口,初始化要綁定的網絡地址結構。
(3)綁定IP地址、端口等信息,使用bind()函數,將套接字文件描述符和一個地址進行綁定。
(4)循環接收客戶端的數據,使用recvfrom()函數接收客戶端的網絡數據。
(5)向客戶端發送數據,使用sendto()函數向服務器主機發送數據。
(6)關閉套接字,使用close()函數釋放資源。UDP協議的客戶端流程
3.2.2 UDP協議的客戶端流程
UDP協議的客戶端流程分為5個部分。
(1)建立套接字文件描述符,socket();
(2)設置服務器IP地址和端口,struct sockaddr;
(3)向服務器發送數據,sendto();
(4)接收服務器的數據,recvfrom();
(5)關閉套接字,close()。
3.3 UDPSocket客戶服務器通信實例
3.3.1 服務端(service.c)
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> #include<errno.h> #include<string.h> #include<stdlib.h>#define SERV_PORT 3000int main() {int sock_fd; //套接子描述符號int recv_num;int send_num;int client_len;char recv_buf[20];struct sockaddr_in addr_serv;struct sockaddr_in addr_client;//服務器和客戶端地址sock_fd = socket(AF_INET,SOCK_DGRAM,0);if(sock_fd < 0){perror("socket");exit(1);} else{printf("sock sucessful\n");}//初始化服務器斷地址memset(&addr_serv,0,sizeof(struct sockaddr_in));addr_serv.sin_family = AF_INET;//協議族addr_serv.sin_port = htons(SERV_PORT);addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地址client_len = sizeof(struct sockaddr_in);/*綁定套接子*/if(bind(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr_in))<0 ){perror("bind");exit(1);} else{ printf("bind sucess\n");}while(1){printf("begin recv:\n");recv_num = recvfrom(sock_fd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&addr_client,&client_len);if(recv_num < 0){printf("bad\n");perror("again recvfrom");exit(1);} else{recv_buf[recv_num]='\0';printf("recv sucess:%s\n",recv_buf);}printf("begin send:\n");send_num = sendto(sock_fd,recv_buf,recv_num,0,(struct sockaddr *)&addr_client,client_len);if(send_num < 0){perror("sendto");exit(1);} else{printf("send sucessful\n");}}close(sock_fd);return 0; }3.3.2 客戶端(client.c)
#include<stdio.h> #include<string.h> #include<errno.h> #include<stdlib.h> #include<unistd.h>#include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h>#define DEST_PORT 3000 #define DSET_IP_ADDRESS "192.168.1.103"int main() {int sock_fd;/*套接字文件描述符*/int send_num;int recv_num;int dest_len;char send_buf[20]={"hello tiger"};char recv_buf[20];struct sockaddr_in addr_serv;/*服務端地址,客戶端地址*/sock_fd = socket(AF_INET,SOCK_DGRAM,0);//創建套接子//初始化服務器端地址memset(&addr_serv,0,sizeof(addr_serv));addr_serv.sin_family = AF_INET;addr_serv.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS);addr_serv.sin_port = htons(DEST_PORT);dest_len = sizeof(struct sockaddr_in);printf("begin send:\n");send_num = sendto(sock_fd,send_buf,sizeof(send_buf),0,(struct sockaddr *)&addr_serv,dest_len);if(send_num < 0){perror("sendto");exit(1);} else{printf("send sucessful:%s\n",send_buf);}recv_num = recvfrom(sock_fd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&addr_serv,&dest_len);if(recv_num <0 ){perror("recv_from");exit(1);} else{printf("recv sucessful\n");}recv_buf[recv_num]='\0';printf("the receive:%s\n",recv_buf);close(sock_fd);return 0; }3.4 UDP編程注意:
1、UDP報文可能會丟失、重復
2、UDP報文可能會亂序
3、UDP缺乏流量控制
4、UDP協議數據報文截斷
5、recvfrom返回0,不代表連接關閉,因為udp是無連接的。
6、ICMP異步錯誤
7、UDP connect
8、UDP外出接口的確定
9、太大的UDP包可能出現的問題
參考鏈接:
https://blog.csdn.net/lell3538/article/details/53335472
https://blog.csdn.net/dongyanxia1000/article/details/80743691
https://blog.csdn.net/weixin_42193813/article/details/105771978
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的基于socket网络编程技术实现TCP和UDP的流程详解及实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解const和#define
- 下一篇: suse 查看java版本_SLES 1