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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux下TCP通信简单实例

發(fā)布時間:2025/6/15 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux下TCP通信简单实例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

linux下TCP通信簡單實例
基于TCP(面向連接)的socket編程,分為服務(wù)器端和客戶端


服務(wù)器端的流程如下:


(1)創(chuàng)建套接字(socket)


(2)將套接字綁定到一個本地地址和端口上(bind)


(3)將套接字設(shè)為監(jiān)聽模式,準(zhǔn)備接收客戶端請求(listen)


(4)等待客戶請求到來;當(dāng)請求到來后,接受連接請求,返回一個新的對應(yīng)于此次連接的套接字(accept)


(5)用返回的套接字和客戶端進(jìn)行通信(send/recv)


(6)返回,等待另一個客戶請求。


(7)關(guān)閉套接字。


客戶端的流程如下:


(1)創(chuàng)建套接字(socket)


(2)向服務(wù)器發(fā)出連接請求(connect)


(3)和服務(wù)器端進(jìn)行通信(send/recv)


(4)關(guān)閉套接字


下面通過一個具體例子講解一下具體的過程和相關(guān)的函數(shù),環(huán)境是suse Linux。


服務(wù)器端:
#include <stdio.h> ? ?
#include <stdlib.h> ? ?
#include <strings.h> ? ?
#include <sys/types.h> ? ?
#include <sys/socket.h> ? ?
#include <memory.h> ? ?
#include <unistd.h> ? ?
//#include <linux/in.h> ? ?
#include <netinet/in.h> ? ?
//#include <linux/inet_diag.h> ? ?
#include <arpa/inet.h> ? ?
? ??
#include <signal.h> ? ?
? ??
/** ?
? 關(guān)于 sockaddr ?sockaddr_in ?socketaddr_un說明 ?
? http://maomaozaoyue.blog.sohu.com/197538359.html ?
? */ ? ?
? ??
#define PORT ? ?11910 ? //定義通信端口 ? ?
#define BACKLOG 5 ? ? ? //定義偵聽隊列長度 ? ?
#define buflen ?1024 ? ?
? ??
void process_conn_server(int s); ? ?
void sig_pipe(int signo); ? ?
? ??
int ss,sc; ?//ss為服務(wù)器socket描述符,sc為某一客戶端通信socket描述符 ? ?
? ??
int main(int argc,char *argv[]) ? ?
{ ? ?
? ??
? ? struct sockaddr_in server_addr; //存儲服務(wù)器端socket地址結(jié)構(gòu) ? ?
? ? struct sockaddr_in client_addr; //存儲客戶端 socket地址結(jié)構(gòu) ? ?
? ??
? ? int err; ? ?//返回值 ? ?
? ? pid_t pid; ?//分叉進(jìn)行的ID ? ?
? ??
? ? /*****************socket()***************/ ? ?
? ? ss = socket(AF_INET,SOCK_STREAM,0); //建立一個序列化的,可靠的,雙向連接的的字節(jié)流 ? ?
? ? if(ss<0) ? ?
? ? { ? ?
? ? ? ? printf("server : server socket create error\n"); ? ?
? ? ? ? return -1; ? ?
? ? } ? ?
? ? //注冊信號 ? ?
? ? sighandler_t ret; ? ?
? ? ret = signal(SIGTSTP,sig_pipe); ? ?
? ? if(SIG_ERR == ret) ? ?
? ? { ? ?
? ? ? ? printf("信號掛接失敗\n"); ? ?
? ? ? ? return -1; ? ?
? ? } ? ?
? ? else ? ?
? ? ? ? printf("信號掛接成功\n"); ? ?
? ??
? ??
? ? /******************bind()****************/ ? ?
? ? //初始化地址結(jié)構(gòu) ? ?
? ? memset(&server_addr,0,sizeof(server_addr)); ? ?
? ? server_addr.sin_family = AF_INET; ? ? ? ? ? //協(xié)議族 ? ?
? ? server_addr.sin_addr.s_addr = htonl(INADDR_ANY); ? //本地地址 ? ?
? ? server_addr.sin_port = htons(PORT); ? ?
? ??
? ? err = bind(ss,(struct sockaddr *)&server_addr,sizeof(sockaddr)); ? ?
? ? if(err<0) ? ?
? ? { ? ?
? ? ? ? printf("server : bind error\n"); ? ?
? ? ? ? return -1; ? ?
? ? } ? ?
? ??
? ? /*****************listen()***************/ ? ?
? ? err = listen(ss,BACKLOG); ? //設(shè)置監(jiān)聽的隊列大小 ? ?
? ? if(err < 0) ? ?
? ? { ? ?
? ? ? ? printf("server : listen error\n"); ? ?
? ? ? ? return -1; ? ?
? ? } ? ?
? ??
? ? /****************accept()***************/ ? ?
? ? /** ?
? ? 為類方便處理,我們使用兩個進(jìn)程分別管理兩個處理: ?
? ? 1,服務(wù)器監(jiān)聽新的連接請求;2,以建立連接的C/S實現(xiàn)通信 ?
? ? 這兩個任務(wù)分別放在兩個進(jìn)程中處理,為了防止失誤操作 ?
? ? 在一個進(jìn)程中關(guān)閉 偵聽套接字描述符 另一進(jìn)程中關(guān)閉 ?
? ? 客戶端連接套接字描述符。注只有當(dāng)所有套接字全都關(guān)閉時 ?
? ? 當(dāng)前連接才能關(guān)閉,fork調(diào)用的時候父進(jìn)程與子進(jìn)程有相同的 ?
? ? 套接字,總共兩套,兩套都關(guān)閉掉才能關(guān)閉這個套接字 ?
? ? */ ? ?
? ??
? ? for(;;) ? ?
? ? { ? ?
? ? ? ? socklen_t addrlen = sizeof(client_addr); ? ?
? ? ? ? //accept返回客戶端套接字描述符 ? ?
? ? ? ? sc = accept(ss,(struct sockaddr *)&client_addr,&addrlen); ?//注,此處為了獲取返回值使用 指針做參數(shù) ? ?
? ? ? ? if(sc < 0) ?//出錯 ? ?
? ? ? ? { ? ?
? ? ? ? ? ? continue; ? //結(jié)束此次循環(huán) ? ?
? ? ? ? } ? ?
? ? ? ? else ? ?
? ? ? ? { ? ?
? ? ? ? ? ? printf("server : connected\n"); ? ?
? ? ? ? } ? ?
? ??
? ? ? ? //創(chuàng)建一個子線程,用于與客戶端通信 ? ?
? ? ? ? pid = fork(); ? ?
? ? ? ? //fork 調(diào)用說明:子進(jìn)程返回 0 ;父進(jìn)程返回子進(jìn)程 ID ? ?
? ? ? ? if(pid == 0) ? ? ? ?//子進(jìn)程,與客戶端通信 ? ?
? ? ? ? { ? ?
? ? ? ? ? ? close(ss); ? ?
? ? ? ? ? ? process_conn_server(sc); ? ?
? ? ? ? } ? ?
? ? ? ? else ? ?
? ? ? ? { ? ?
? ? ? ? ? ? close(sc); ? ?
? ? ? ? } ? ?
? ? } ? ?
} ? ?
? ??
/** ?
? 服務(wù)器對客戶端連接處理過程;先讀取從客戶端發(fā)送來的數(shù)據(jù), ?
? 然后將接收到的數(shù)據(jù)的字節(jié)的個數(shù)發(fā)送到客戶端 ?
? */ ? ?
? ??
//通過套接字 s 與客戶端進(jìn)行通信 ? ?
void process_conn_server(int s) ? ?
{ ? ?
? ? ssize_t size = 0; ? ?
? ? char buffer[buflen]; ?//定義數(shù)據(jù)緩沖區(qū) ? ?
? ? for(;;) ? ?
? ? { ? ?
? ? ? ? //等待讀 ? ?
? ? ? ? for(size = 0;size == 0 ;size = read(s,buffer,buflen)); ? ?
? ? ? ? //輸出從客戶端接收到的數(shù)據(jù) ? ?
? ? ? ? printf("%s",buffer); ? ?
? ??
? ? ? ? //結(jié)束處理 ? ?
? ? ? ? if(strcmp(buffer,"quit") == 0) ? ?
? ? ? ? { ? ?
? ? ? ? ? ? close(s); ? //成功返回0,失敗返回-1 ? ?
? ? ? ? ? ? return ; ? ?
? ? ? ? } ? ?
? ? ? ? sprintf(buffer,"%d bytes altogether\n",size); ? ?
? ? ? ? write(s,buffer,strlen(buffer)+1); ? ?
? ? } ? ?
} ? ?
void sig_pipe(int signo) ? ?
{ ? ?
? ? printf("catch a signal\n"); ? ?
? ? if(signo == SIGTSTP) ? ?
? ? { ? ?
? ? ? ? printf("接收到 SIGTSTP 信號\n"); ? ?
? ? ? ? int ret1 = close(ss); ? ?
? ? ? ? int ret2 = close(sc); ? ?
? ? ? ? int ret = ret1>ret2?ret1:ret2; ? ?
? ? ? ? if(ret == 0) ? ?
? ? ? ? ? ? printf("成功 : 關(guān)閉套接字\n"); ? ?
? ? ? ? else if(ret ==-1 ) ? ?
? ? ? ? ? ? printf("失敗 : 未關(guān)閉套接字\n"); ? ?
? ??
? ? ? ? exit(1); ? ?
? ? } ? ?
} ? ?


客戶端:
#include <stdio.h> ? ?
? ? #include <strings.h> ? ?
? ? #include <unistd.h> ? ?
? ? #include <sys/types.h> ? ?
? ? #include <sys/socket.h> ? ?
? ? //#include <linux/in.h> ? ?
? ? #include <stdlib.h> ? ?
? ? #include <memory.h> ? ?
? ? #include <arpa/inet.h> ? ?
? ? #include <netinet/in.h> ? ?
? ? ? ??
? ? #include <signal.h> //添加信號處理 ?防止向已斷開的連接通信 ? ?
? ? ? ??
? ? /** ?
? ? ? 信號處理順序說明:在Linux操作系統(tǒng)中某些狀況發(fā)生時,系統(tǒng)會向相關(guān)進(jìn)程發(fā)送信號, ?
? ? ? 信號處理方式是:1,系統(tǒng)首先調(diào)用用戶在進(jìn)程中注冊的函數(shù),2,然后調(diào)用系統(tǒng)的默認(rèn) ?
? ? ? 響應(yīng)方式,此處我們可以注冊自己的信號處理函數(shù),在連接斷開時執(zhí)行 ?
? ? ? */ ? ?
? ? ? ??
? ? ? ??
? ? #define PORT ? ?11910 ? ?
? ? #define Buflen ?1024 ? ?
? ? ? ??
? ? void process_conn_client(int s); ? ?
? ? void sig_pipe(int signo); ? ?//用戶注冊的信號函數(shù),接收的是信號值 ? ?
? ? ? ??
? ? int s; ?//全局變量 , 存儲套接字描述符 ? ?
? ? ? ??
? ? int main(int argc,char *argv[]) ? ?
? ? { ? ?
? ? ? ??
? ? ? ? sockaddr_in server_addr; ? ?
? ? ? ? int err; ? ?
? ? ? ? sighandler_t ret; ? ?
? ? ? ? char server_ip[50] = ""; ? ?
? ? ? ? int port = 0; ?
? ? ? ? strcpy(server_ip, argv[1]); ?
? ? ? ? port = atoi(argv[2]); ?
??
? ? ? ? /********************socket()*********************/ ? ?
? ? ? ? s= socket(AF_INET,SOCK_STREAM,0); ? ?
? ? ? ? if(s<0) ? ?
? ? ? ? { ? ?
? ? ? ? ? ? printf("client : create socket error\n"); ? ?
? ? ? ? ? ? return 1; ? ?
? ? ? ? } ? ?
? ? ? ? printf("client : socket fd = %d\n", s); ??
? ? ? ? //信號處理函數(shù) ?SIGINT 是當(dāng)用戶按一個 Ctrl-C 建時發(fā)送的信號 ? ?
? ? ? ? ret = signal(SIGTSTP,sig_pipe); ? ?
? ? ? ? if(SIG_ERR == ret) ? ?
? ? ? ? { ? ?
? ? ? ? ? ? printf("信號掛接失敗\n"); ? ?
? ? ? ? ? ? return -1; ? ?
? ? ? ? } ? ?
? ? ? ? else ? ?
? ? ? ? ? ? printf("信號掛接成功\n") ; ? ?
? ? ? ??
? ? ? ??
? ? ? ? /*******************connect()*********************/ ? ?
? ? ? ? //設(shè)置服務(wù)器地址結(jié)構(gòu),準(zhǔn)備連接到服務(wù)器 ? ?
? ? ? ? memset(&server_addr,0,sizeof(server_addr)); ? ?
? ? ? ? server_addr.sin_family = AF_INET; ? ?
? ? ? ? server_addr.sin_port = htons(PORT); ? ?
? ? ? ? server_addr.sin_addr.s_addr = htonl(INADDR_ANY); ? ?
? ? ? ??
? ? ? ? /*將用戶數(shù)入對額字符串類型的IP格式轉(zhuǎn)化為整型數(shù)據(jù)*/ ? ?
? ? ? ? //inet_pton(AF_INET,argv[1],&server_addr.sin_addr.s_addr); ? ?
? ? ? ? printf("please input server ip address : \n"); ? ?
? ? ? ? read(0,server_ip,50); ? ?
? ? ? ? //err = inet_pton(AF_INET,server_ip,&server_addr.sin_addr.s_addr); ? ?
? ? ? ? server_addr.sin_addr.s_addr = inet_addr(server_ip); ? ?
? ? ? ??
? ? ? ? err = connect(s,(struct sockaddr *)&server_addr,sizeof(sockaddr)); ? ?
? ? ? ? if(err == 0) ? ?
? ? ? ? { ? ?
? ? ? ? ? ? printf("client : connect to server\n"); ? ?
? ? ? ? } ? ?
? ? ? ? else ? ?
? ? ? ? { ? ?
? ? ? ? ? ? printf("client : connect error\n"); ? ?
? ? ? ? ? ? return -1; ? ?
? ? ? ? } ? ?
? ? ? ? //與服務(wù)器端進(jìn)行通信 ? ?
? ? ? ? process_conn_client(s); ? ?
? ? ? ? close(s); ? ?
? ? ? ??
? ? } ? ?
? ? void process_conn_client(int s) ? ?
? ? { ? ?
? ? ? ??
? ? ? ? ssize_t size = 0; ? ?
? ? ? ? char buffer[Buflen]; ? ?
? ? ? ??
? ? ? ? for(;;) ? ?
? ? ? ? { ? ?
? ? ? ? ? ? memset(buffer,'\0',Buflen); ? ?
? ? ? ? ? ? /*從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)放到緩沖區(qū)buffer中*/ ? ?
? ? ? ? ? ? size = read(0,buffer,Buflen); ? // 0,被默認(rèn)的分配到標(biāo)準(zhǔn)輸入 ?1,標(biāo)準(zhǔn)輸出 ?2,error ? ?
? ? ? ? ? ? if(size > ?0) ? ?
? ? ? ? ? ? { ? ?
? ? ? ? ? ? ? ? //當(dāng)向服務(wù)器發(fā)送 “quit” 命令時,服務(wù)器首先斷開連接 ? ?
? ? ? ? ? ? ? ? write(s,buffer,strlen(buffer)+1); ? //向服務(wù)器端寫 ? ?
? ? ? ??
? ? ? ? ? ? ? ? //等待讀取到數(shù)據(jù) ? ?
? ? ? ? ? ? ? ? for(size = 0 ; size == 0 ; size = read(s,buffer,Buflen) ); ? ?
? ? ? ??
? ? ? ? ? ? ? ? write(1,buffer,strlen(buffer)+1); ? //向標(biāo)準(zhǔn)輸出寫 ? ?
? ? ? ? ? ? } ? ?
? ? ? ? } ? ?
? ? } ? ?
? ? ? ??
? ? void sig_pipe(int signo) ? ?//傳入套接字描述符 ? ?
? ? { ? ?
? ? ? ? printf("Catch a signal\n"); ? ?
? ? ? ? if(signo == SIGTSTP) ? ?
? ? ? ? { ? ?
? ? ? ??
? ? ? ? ? ? printf("接收到 SIGTSTP 信號\n"); ? ?
? ? ? ? ? ? int ret = close(s); ? ?
? ? ? ? ? ? if(ret == 0) ? ?
? ? ? ? ? ? ? ? printf("成功 : 關(guān)閉套接字\n"); ? ?
? ? ? ? ? ? else if(ret ==-1 ) ? ?
? ? ? ? ? ? ? ? printf("失敗 : 未關(guān)閉套接字\n"); ? ?
? ? ? ? ? ? exit(1); ? ?
? ? ? ? } ? ?
? ? } ?

總結(jié)

以上是生活随笔為你收集整理的linux下TCP通信简单实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。