說明:
??本文章旨在總結備份、方便以后查詢,由于是個人總結,如有不對,歡迎指正;另外,內容大部分來自網路、書籍、和各類手冊,如若侵權請告知,馬上刪帖致歉,
??QQ 群 號:513683159 【相互學習】
內容來源:
??《Linux網路編程》
功能描述:
??客戶端連接服務器后從標準輸入讀取字串發送給服務器,
??服務器接收到字串后,發送接收到的總字串個數給客戶端、
??客戶端將接受到的服務器資訊列印到標準輸出,
??整個程序流程如下:

源檔案
服務器端源檔案:tcp_server.c
/**
* Step 1 : 初始化作業
* 1.頭檔案
* 2.宏定義:偵聽埠地址與偵聽佇列長度
* 3.函式宣告:服務器對客戶端的處理函式,位于:tcp_process.c
* 4.變數:定義并初始化
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 8888 //偵聽埠地址:8888
#define BACKLOG 2 //偵聽佇列長度:2
extern void process_conn_server(int s); //服務器對客戶端的處理:讀取資料并發送回應字符
int main(int argc,char *argv[])
{
int ss = 0; //ss = server socket = 服務器socket描述符
int cs = 0; //cs = client socket = 客戶端socket描述符
struct sockaddr_in server_addr; //服務器地址結構
struct sockaddr_in client_addr; //客戶端地址結構
int ret = 0; //回傳值
pid_t pid; //行程ID
/**
* Step 2 : 建立套接字
*/
ss = socket(AF_INET,SOCK_STREAM,0); //創建一個AF_INET族的流型別socket
if(ss < 0) //檢查是否正常創建socket
{
perror("socket error\n");
exit(EXIT_FAILURE);
}
/**
* Step 3 : 設定服務器地址
* Note:
* htonl():將主機數轉換成無符號長整型的網路位元組順序
* htons():將整型變數從主機位元組順序轉變成網路位元組順序
*/
bzero(&server_addr,sizeof(server_addr)); //清零
server_addr.sin_family = AF_INET; //設定地址族為AF_INET
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本地地址
server_addr.sin_port = htons(PORT); //設定埠號
/**
* Step 4 : 系結地址結構到套接字描述符
*/
ret = bind(ss,(struct sockaddr*)&server_addr,sizeof(server_addr));
if (ret < 0) //出錯
{
perror("bind error\n");
exit(EXIT_FAILURE);
}
/**
* Step 5 : 設定偵聽,偵聽佇列長度為2,可同時處理兩個客戶端連接請求
*/
ret = listen(ss,BACKLOG);
if (ret < 0) //出錯
{
perror("bind error\n");
exit(EXIT_FAILURE);
}
/**
* Step 6 : 主回圈程序
*/
for(;;)
{
/* 接收客戶端連接 */
int addrlen = sizeof(struct sockaddr);
cs = accept(ss,(struct sockaddr*)&client_addr,&addrlen);
if(cs < 0) //出錯
{
continue; //結束本次回圈
}
/* 建立一個新的行程處理到來的連接 */
pid = fork(); //創建新行程
if(pid < 0) /* pid < 0,fork失敗 */
{
printf("fork error\n");
}
else if(pid == 0) /* pid = 0,子行程 */
{
close(ss); //子行程中關閉服務器的偵聽
process_conn_server(cs); //處理連接
}
else /* pid > 0,父行程 */
{
close(cs); //父行程中關閉客戶端的連接
}
}
return 0;
}
客戶端源檔案:tcp_client.c
/**
* Step 1 : 初始化作業
* 1.頭檔案
* 2.宏定義:偵聽埠地址
* 3.函式宣告:服務器對客戶端的處理函式,位于:tcp_process.c
* 4.變數:定義并初始化
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888 //埠地址:8888
extern void process_conn_client(int s);
int main(int argc,char *argv[])
{
int s = 0; //socket描述符
struct sockaddr_in server_addr; //服務器地址結構
int ret = 0; //回傳值
/**
* Step 2 : 建立套接字
*/
s = socket(AF_INET,SOCK_STREAM,0); //創建一個AF_INET族的流型別socket
if(s < 0) //檢查是否正常創建socket
{
perror("socket error\n");
exit(EXIT_FAILURE);
}
/**
* Step 3 : 設定服務器地址
*/
bzero(&server_addr,sizeof(server_addr)); //清零
server_addr.sin_family = AF_INET; //設定地址族為AF_INET
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本地地址
server_addr.sin_port = htons(PORT); //設定埠號
/**
* Step 4 : 將用戶輸入的字串型別的IP地址轉為整型
*/
inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
/**
* Step 5 : 連接服務器
*/
connect(s,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
process_conn_client(s); //客戶端處理程序
close(s); //關閉連接
}
處理源檔案:tcp_process.c
#include <string.h>
#include <stdio.h>
#include <unistd.h>
/* 服務器對客戶端處理函式*/
void process_conn_server(int s)
{
ssize_t size = 0;
char buffer[1024]; //資料的緩沖區
for (;;) //回圈處理程序
{
size = read(s,buffer,1024); //從套接字中讀取資料放到緩沖區buffer中
if(size == 0) //沒有資料
{
return;
}
/* 構建回應字符,為接收到客戶端位元組的數量 */
sprintf(buffer,"%ld bytes altogether\n",size);
write(s,buffer,strlen(buffer)+1); //發給客戶端
}
}
/* 客戶端的處理程序 */
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024]; //資料的緩沖區
for(;;)
{
/* 從標準輸入中讀取資料放到緩沖區buffer中 */
size = read(0,buffer,1024);
if(size > 0) //讀到資料
{
write(s,buffer,size); //發送給服務器
size = read(s,buffer,1024); //從服務器讀取資料
write(1,buffer,size); //寫到標準輸出,0表示標準輸入,1表示標準輸出
}
}
}
Makefile檔案
all:client server #all規則,依賴于client和server規則
client:tcp_process.o tcp_client.o #client規則,生成客戶端可執行程式
gcc -o client tcp_process.o tcp_client.o
server:tcp_process.o tcp_server.o #server規則,生成服務器端可執行程式
gcc -o server tcp_process.o tcp_server.o
clean: #清理規則,洗掉client、server和中間檔案
rm -f client server *.o
編譯并運行
??將上面檔案全部置于同一目錄下,
??1??編譯:
????執行命令:make,結果如下:
cc -c -o tcp_process.o tcp_process.c #生成tcp_process.o中間檔案
cc -c -o tcp_client.o tcp_client.c #生成tcp_client.o中間檔案
gcc -o client tcp_process.o tcp_client.o #由tcp_process.o與tcp_client.o生成可執行檔案:client
cc -c -o tcp_server.o tcp_server.c #生成tcp_server.o中間檔案
gcc -o server tcp_process.o tcp_server.o #由tcp_process.o與tcp_server.o生成可執行檔案:server
??2??運行:
????①打開終端,執行命令:./server
????會執行服務端可執行程式server,該程式會在埠8888上偵聽,等待客戶端的連接請求,
????②另起終端,執行命令:./client 127.0.0.1
????會執行服務端可執行程式client ,該程式會連接上服務器
????緊接著輸入字串就會有相應,效果如下:
hhb@xsndz:/home/hhb/桌面/tcp$ ./client 127.0.0.1
nihao
6 bytes altogether
shiyishi
9 bytes altogether
查詢網路連接情況
??在程式正常運行的狀態,再另起終端,使用netstat命令查詢網路連接情況,
??執行指令:netstat,效果如下:
激活Internet連接 (w/o 服務器)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:39460 localhost:8888 ESTABLISHED
tcp 0 0 localhost:8888 localhost:39460 ESTABLISHED
??其中8888為服務器端的埠,39460為客戶端的埠
??服務器和客戶端段通過這兩個埠建立了連接,
服務器端與客戶端程式設計模式

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/356767.html
標籤:其他
上一篇:網路編程補充
