tcp_servet

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

static void usage(const char* proc)
{
printf(\”Usage: %s [local_ip] [local_port]\”,proc);//提示輸入出錯,應該輸入./tcp_servet ip地址 端口號(運行服務器)
}

int startup(const char* ip,int port)//創建套接字
{
int sock = socket(AF_INET,SOCK_STREAM,0);//socket()創建套接字函數
if(sock<0)
{
perror(\”socket\”);//提示創建套接字失敗
exit(2);
}

//socket的返回值只是一個文件描述符,為了進行網絡通信,我們還需將其與服務器 ip地址和端口號進行綁定

struct sockaddr_in local;//結構體struct sockaddr_in是struct sockaddr的具體化
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);

if(bind(sock,(struct sockaddr*) &local,sizeof(local))<0){//bind(綁定函數
perror(\”bind\”);
exit(3);
}
//監聽
if(listen(sock,10)<0)//服務器24小時監聽,等待連接請求
{
perror(\”listen\”);
exit(4);
}
return sock;
}

//Version 1
//./tcp_servet 127.0.0.1 8080 本地環回
int main(int argc,char* argv[])
{
if(argc!=3){
usage(argv[0]);
return 1;
}

int listen_sock = startup(argv[1],atoi(argv[2]));//create socket

int new_sock;
while(1){
struct sockaddr_in client;
socklen_t len = sizeof(client);

new_sock = accept(listen_sock,(struct sockaddr*)&client ,&len);//accept創建新的socket,用來處理客戶段請求,listen_sock只負責監聽
if(new_sock<0)
{
perror(\”accept\”);
exit(5);
continue;
}
//成功獲取到客戶端,打印客戶端的 ip和端口號,accept的第二個參數是輸出型參數,由它可得客戶端的ip和端口號
printf(\”get an new client: %s, %d\\n\”,inet_ntoa(client.sin_addr),ntohs(client.sin_port));
break;
}

//客戶端和服務器端的數據傳輸
char buf[1024];
while(1){
int r = read(new_sock,buf,sizeof(buf)-1);//從網絡中讀取數據(客戶端發送數據)放入buf中;
if(r<0){//讀取失敗
perror(\”read\”);
close(new_sock);
break;
}else if(r==0){//客戶端已關閉
close(new_sock);
printf(\”client qiuit…\\n\”);
break;
}

//讀取成功
buf[r] = 0;
printf(\”clinet: %s\\n\”,buf);
write(new_sock,buf,strlen(buf));//回送數據
}

return 0;
}

tcp_client.c客戶端

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>

void static Usage(const char* proc)//提示打印格式
{
printf(\”Usage: %s [local_ip] [local_port]\\n\”,proc);//運行客戶端./tcp_servet 服務器ip 服務器端口號
}

//./tcp_clinet servet_ip servet_port
int main(int argc,char* argv[])
{
if(argc!=3){
Usage(argv[1]);
exit(1);
}

int sock = socket(AF_INET,SOCK_STREAM,0);//創建套接字
if(sock < 0 ){
perror(\”socket\”);
exit(2);
}
//客戶端socket不綁定
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));//htons將本地端口號轉為網絡端口號
server.sin_addr.s_addr = inet_addr(argv[1]); //給數據結構成員賦值
//connect()鏈接服務器
if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0){
perror(\”connect\”);
exit(3);
}
//客戶端發送數據
char buf[1024];
while(1){
printf(\”Please Enter$\”);
fflush(stdout);

ssize_t s = read(0,buf,sizeof(buf)-1);//從標準輸入讀數據到buf
if(s>0){//讀取成功
buf[s-1] = 0;
write(sock,buf,strlen(buf));//將數據寫到網絡中
s = read(sock,buf,sizeof(buf)-1);//讀取回顯數據
if(s>0){
buf[s] = 0;
printf(\”servetr echo#:%s\\n\”,buf);
}
}
return 0;
}

注意要點

上述的服務器地址采用127.0.0.1,故該服務器沒有通過網絡通信,還是一直監聽所在主機上的客戶鏈接請求,這是本地環回;

該客戶/服務器是一個單進程的服務器,一次只能鏈接一個客戶請求,因為我們在收到一個客戶請求后,執行完客戶端的請求才接受下一個請求的鏈接

客戶端的套接字可以綁定也可以不綁定,但一般不進行綁定,因為一點綁定服務器的ip,那么若別的客戶端想鏈接,鏈接不上

涉及函數以及命令

創建socket

domain表示域,ipv4為AF_INET;
type表示類型,SOCK_STREAM(面向字節流)
protocal表示協議,單個通信協議情況下為0

bind綁定

sockfd : socket()的返回值,一個文件描述符
addr:一個struct sockaddr_in 的結構體

struct in_addr結構體成員是s_addr,表示ip地址;
addrlen:結構體大小

accept創建新的socket

addr是一個輸出型參數,輸出的是客戶端的struct sockaddr_in 的內容
addrlen是一個輸入輸出型參數
ip轉換

本地端口號與網絡端口號的互換

監聽

backlog : 是操作系統底層連接隊列,不能設置過大;
connect函數(客戶端連接服務器)

2.多進程服務器編寫

代碼清單:
tcp_servet.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

//Version2

void static usage(const char* proc)
{
printf(\”Usage: %s [local_ip] [local_port]\\n\”,proc);
}

int startup(char* _ip,int _port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0){
perror(\”socket\”);
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = inet_addr(_ip);

if(bind(sock,(struct sockaddr*) &local,sizeof(local))<0){
perror(\”bind\”);
exit(3);
}

if(listen(sock,10)<0){
perror(\”listen\”);
exit(4);
}
return sock;
}

//./tcp_servet local_ip local_port
int main(int argc,char* argv[]){
if(argc!=3){
usage(argv[0]);
return 1;
}

int listen_sock = startup(argv[1],atoi(argv[2]));

int new_sock;
while(1){
struct sockaddr_in client;
socklen_t len = sizeof(client);
new_sock = accept(listen_sock,(struct sockaddr*) &client,&len);
if(new_sock < 0){
perror(\”accept\”);
exit(5);
continue;
}
printf(\”get an new client:%s,%d\\n\”,inet_ntoa(client.sin_addr),ntohs(client.sin_port));
break;
}

//創建了一個子進程代替我們處理客戶端的請求—與上述單進程的不同之處
pid_t id = fork();
if(id<0){
perror(\”fork\”);
exit(6);
}else if(id==0){//child
close(listen_sock);//關閉不必要的文件
if(fork > 0){//兩次fork
exit(7);
}

char buf[1024];
while(1){
int r= read(new_sock);
if(r<0){
perror(\”read\”);
close(new_sock);
break;
}else if(r==0){
close(new_sock);
printf(\”clinet quit…\\n\”);
break;
}
buf[r] = 0;
printf(\”clien: %S\\n\”,buf);
write(new_sock,buf,strlen(buf));
close(new_sock);
}

}else{//father
close(new_sock);//父進程繼續負責監聽客戶請求,必須關閉new_sock文件
}
}

注意要點

與單進程的唯一不同的是, fork了一個子進程,每次客戶端的請求交給子進程完成,父進程只負責監聽 ;
兩次 fork,為了能夠讓父進程只負責監聽,而不阻塞式的等待子進程的退出,我們采用兩次fork,此時存在兩個進程,兩個進程存在爺孫關系,“孫子”進程此時由于父進程已經退出,所以它是孤兒進程,由 init進程回收,與此刻的父進程沒有關系

pid_t id = fork();
if(id<0){
perror(\”fork\”);
exit(6);
}else if(id==0){//child
close(listen_sock);//關閉不必要的文件
if(fork > 0){//兩次fork,第二次創建完子進程后該父進程退出
exit(7);
}

父進程必須關閉new_sock文件,因為子進程拷貝了父進程的文件描述符表,兩者表是一樣的,若不關閉,每次客戶端發送來一個新的連接,就要在父進程的文件描述符表中打開一個文件,這樣浪費資源,而且很快會用完;(子進程處理完信息后退出時關閉了文件描述符表,而父進程一直處于運行狀態,所以必須主動關閉)

3.多線程服務器的編寫

代碼:

更多關于云服務器域名注冊,虛擬主機的問題,請訪問三五互聯官網:www.shinetop.cn

贊(0)
聲明:本網站發布的內容(圖片、視頻和文字)以原創、轉載和分享網絡內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。郵箱:3140448839@qq.com。本站原創內容未經允許不得轉載,或轉載時需注明出處:三五互聯知識庫 » 多進程多線程服務器(tcp_server)編寫

登錄

找回密碼

注冊

主站蜘蛛池模板: 久久精品国产亚洲av天海翼| av色国产色拍| 中文有无人妻vs无码人妻激烈| 国产又爽又黄的激情视频| 怡红院一区二区三区在线| 欧美一本大道香蕉综合视频 | 国产精品乱码久久久久久小说| 少妇被粗大的猛烈进出69影院一 | 婷婷丁香五月亚洲中文字幕| 亚洲人妻一区二区精品| 亚洲国产亚洲综合在线尤物| 国产三级精品三级在专区| 午夜精品极品粉嫩国产尤物| 人成午夜免费大片| 国产一区二区三区禁18| 国产精品视频亚洲二区| 中国CHINA体内裑精亚洲日本| 成人自拍短视频午夜福利| 91青青草视频在线观看的| 麻豆亚州无矿码专区视频| 日韩av一区二区精品不卡| 日韩av片无码一区二区三区| 亚洲女初尝黑人巨| 精品乱人伦一区二区三区| 国产精品欧美亚洲韩国日本久久| 熟女亚洲综合精品伊人久久| 综合偷自拍亚洲乱中文字幕 | 亚洲无线码中文字幕在线| 免费A级毛片无码A∨蜜芽试看 | 卢湾区| 欧美熟妇xxxxx欧美老妇不卡| 镇原县| 中美日韩在线一区黄色大片| 丁香五月亚洲综合在线国内自拍 | 亚洲αⅴ无码乱码在线观看性色| 香蕉久久一区二区不卡无毒影院| 日韩一区二区三区理伦片| 国产精品小粉嫩在线观看| 国产睡熟迷奷系列网站| 久久亚洲精品中文字幕波多野结衣| 国产日产亚洲系列av|