Linux網路程式設計(2)——採用TCP的基本server的實現
一個基本的C/S伺服器模型很簡單: 客戶端 <------------------------> 伺服器
簡而言之就是客戶端跟伺服器之間的通話,通話方式一般採用TCP和UDP這兩種。
TCP和UDP區別
1、Tcp提供客戶與伺服器之間的連線。TCP客戶端先與某個給定伺服器建立一個連線,再跨該連線於那個伺服器交換資料,然後終止這個連線。
(連線其實就是一種協商機制,預先定義好了雙方的一些狀態變數,告訴對方諸如序列號和通告視窗大小等狀態資訊)
2、Tcp提供了可靠的傳輸機制,不需要像UDP那樣需要通過應用層來實現可靠性,直接通過協議來實現。傳送資料後等待對方確認,沒有收到確認就繼續重傳與等待,數次重傳失敗後才會放棄。
3、Tcp提供了流量控制,tcp總是告訴對端在任何時刻它一次能夠從對端接收多少位元組的資料。
採用套接字的TCP連線的基本程式模型
就是通過socket的這個函式封裝資料,實現server額client的通訊
客戶端 服務端
sokcket socket() //建立套接字描述符
bind() //將伺服器地址和相應套接字描述符繫結
listen() //將主動套接字轉換為監聽套接字,該套接字可以接受來自客戶端的請求
connect() <-------------> accept() //connect()客戶端連線請求 , accpet()函式解析監聽來的客戶端資訊,
write() ------------> read() //網路讀寫io
read() <-------------- write()
close() ------------> read()
close() //close關閉連線
函式介面
1、socket
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
若成功返回非負描述符,若出錯返回-1
domain網路型別(一般預設為AF_INET因特網),type套接字型別(一般預設為SOCK_STREAM),protocol協議號
2、connect
#include<sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
若成功返回0,若出錯返回-1
connect函式試圖與套接字地址為serv_addr的伺服器建立一個因特網連線,addrlen預設為sizeof(sockaddr_in)
3、bind
#include<sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
若成功返回0,若出錯返回-1
將伺服器地址和套接字聯絡起來
4、listen
#include<sys/socket.h>
int listen(int sockfd, int backlog);
若成功返回0,若出錯返回-1
告訴核心,這個是伺服器建立的套接字,不是客戶端的,將主動狀態轉換為被動狀態。
5、accept
#include<sys/socket.h>
int accept(int listenfd, struct sockaddr *addr, int *addrlen);若成功返回0,若出錯返回-1
等待來自於客戶端的連線請求到達監聽描述符listenfd,然後在addr中填寫客戶端的套接字地址,並返回一個已連線描述符,這個描述符可以用來利用Unix I/O函式與客戶端通訊。套接字地址結構體
<netinet/in.h>
struct in_addr{
in_addr_t s_addr; //32bit ipv4 address
}
struct sockaddr_in{
uint8_t;
sa_family_t sin_family; // AF_INET
in_port_t sin_port; //埠
struct in_addr sin_addr;
char sin_zero[8]; //未使用
};
DNS主機條目結構體
通過呼叫gethostbyname和gethostbyaddr函式,從DNS資料庫中檢索任意的主機條目。
<pre name="code" class="cpp">#include <netdb.h>
struct hostent{ char *h_name; // 主機域名 char **h_aliases; int h_addrtype; //主機地址 int h_length; char **h_addr_list;};
struct hostent* gethostbyname(const char* name);
struct hostent* gethostbyaddr(const char* addr, int len, int domain);
具體程式碼實現:
實現一個簡單的客戶端伺服器模型,並不涉及多執行緒、I/O複用此類
server.c 服務端
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#define MAX_LISTEN 1024
#define MAX_LINE 1024
int Socket(int domain, int type, int protocol){
int sockfd = socket(domain, type, protocol);
if ( sockfd < 0 ){
perror("init socket: ");
exit(0);
}
return sockfd;
}
void Bind(int sockfd, struct sockaddr *myaddr, int addrlen){
if ( bind(sockfd, myaddr, addrlen) < 0 ){
perror("bind");
exit(0);
} }
void Listen(int sockfd, int backlog){
if ( listen(sockfd, backlog) < 0){
perror("listen");
exit(0);
}
}
int Accept(int listenfd, struct sockaddr *addr, int *addrlen){
int clientfd = accept(listenfd, addr, addrlen);
if ( clientfd < 0){
perror("accept");
exit(0);
}
return clientfd;
}
void Close(int clientfd){
if ( close(clientfd) < 0){
perror("close");
exit(0);
}
}
struct hostent* Gethostbyaddr(const char *addr, int len, int domain){
struct hostent* host = gethostbyaddr(addr, len, domain);
if ( NULL == host ){
perror("host_by_addr");
exit(0);
}
return host;
}
ssize_t Read(int fd, void* buf, size_t n){
ssize_t num= read(fd, buf, n);
if ( n < 0){
perror("read");
exit(0);
}
return num;
}
ssize_t Write(int fd, const void* buf, size_t n){
ssize_t num = read(fd, buf, n);
if ( n < 0){
perror("write");
exit(0);
}
return num;
}
void echo(listenfd){
ssize_t n;
char write_buff[MAX_LINE];
char read_buff[MAX_LINE];
memset(write_buff, 0, MAX_LINE);
memset(read_buff, 0, MAX_LINE);
n = read(listenfd, read_buff, MAX_LINE);
read_buff[n] = '\0';
strcpy(write_buff, "from server echo: ");
strcpy(write_buff+strlen("from server echo: "), read_buff);
n = write(listenfd, write_buff, MAX_LINE);
}
int main(int argc, char **argv){
int servfd, clientfd, port, clientlen;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
struct hostent *host;
char* hostaddr;
if ( argc != 2){
fprintf(stderr,"usage:%s<port>\n", argv[0]);
exit(0);
}
port = atoi(argv[1]); // get port
servfd = Socket(AF_INET, SOCK_STREAM, 0);
// init servaddr
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons((unsigned short)port);
clientlen = sizeof(cliaddr);
Bind(servfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
Listen(servfd, MAX_LISTEN);
while(1){ // init server
memset(&cliaddr, 0, sizeof(cliaddr));
clientfd = Accept(servfd, (struct sockaddr*)&cliaddr, &clientlen);
host = Gethostbyaddr((const char*)&cliaddr.sin_addr.s_addr, sizeof(cliaddr.sin_addr.s_addr), AF_INET);
printf("server connect to host: %s %s\n",host->h_name, inet_ntoa(cliaddr.sin_addr));
echo(clientfd);
Close(clientfd);
}
}
client.c 客戶端
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<netdb.h>
#define MAX_LINE 1024
int Socket(int domain, int type, int protocol){
int sockfd = socket(domain, type, protocol);
if ( sockfd < 0 ){
perror("init socket");
exit(0);
}
return sockfd;
}
void Close(int clientfd){
if ( close(clientfd) < 0){
perror("close");
exit(0);
}
}
struct hostent* Gethostbyaddr(const char *addr, int len, int domain){
struct hostent* host = gethostbyaddr(addr, len, domain);
if ( NULL == host ){
perror("host_by_addr");
exit(0);
}
return host;
}
ssize_t Read(int fd, void* buf, size_t n){
if ( read(fd, buf, n) < 0){
perror("read");
exit(0);
}
}
ssize_t Write(int fd, const void* buf, size_t n){
if ( write(fd, buf, n) < 0){
perror("write");
exit(0);
}
}
void Connect(int sockfd, struct sockaddr* serv_addr, int addrlen){
if ( connect(sockfd, serv_addr, addrlen) < 0){
perror("connect");
exit(0);
}
}
void message_handle(int clientfd){
size_t n;
char send_buff[MAX_LINE];
char recv_buff[MAX_LINE];
memset(send_buff, 0, MAX_LINE);
memset(recv_buff, 0, MAX_LINE);
fgets(send_buff, MAX_LINE, stdin);
send_buff[strlen(send_buff)-1] = '\0';
n = Write(clientfd, send_buff, strlen(send_buff)+1);
n = Read(clientfd, recv_buff, MAX_LINE);
printf("%s \n", recv_buff);
}
int main(int argc, char **argv){
int clientfd, port;
struct sockaddr_in servaddr;
if ( argc != 3){
fprintf(stderr,"usage:%s<addr> <port>\n", argv[0]);
exit(0);
}
port = atoi(argv[2]);
printf("port: %d\n", port);
printf("addr: %s\n", argv[1]);
clientfd = Socket(AF_INET, SOCK_STREAM, 0);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(clientfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
message_handle(clientfd);
Close(clientfd);
}
程式碼分析:
服務端按上圖TCP模型建立伺服器處理客戶端連線,每當有客戶端連線時即列印客戶資訊,然後接受到客戶發來的訊息後,將客戶訊息反射回客戶端。
執行結果:
客戶端:
服務端:
客戶端中斷後使用netstat -a 命令檢視tcp連線狀態,9000埠處於listen狀態,該連線處於TIME_WAIT狀態
相關文章
- UDP&TCP Linux網路應用程式設計詳解UDPTCPLinux程式設計
- JAVA網路程式設計(2)TCP程式設計Java程式設計TCP
- 計算機網路之八:TCP協議(2) TCP可靠傳輸的實現計算機網路TCP協議
- 網路通訊2:TCP通訊實現TCP
- TCP併發伺服器的程式設計實現TCP伺服器程式設計
- Java 網路程式設計 – TCP協議基本步驟Java程式設計TCP協議
- 基本TCP套接字程式設計APITCP程式設計API
- python網路-Socket之TCP程式設計(26)PythonTCP程式設計
- Python網路程式設計實現TCP和UDP連線Python程式設計TCPUDP
- JAVASE網路程式設計之TCP實現聊天通訊Java程式設計TCP
- Java:基於TCP協議網路socket程式設計(實現C/S通訊)JavaTCP協議程式設計
- java多執行緒實現TCP網路Socket程式設計(C/S通訊)Java執行緒TCP程式設計
- Linux網路程式設計(2)Linux程式設計
- socket程式設計在TCP中的應用程式設計TCP
- Linux Socket C語言網路程式設計:TCP SocketLinuxC語言程式設計TCP
- 【Linux系統程式設計】libevent庫實現簡易tcp伺服器Linux程式設計TCP伺服器
- 【網路程式設計】Tcp/Udp程式設計TCPUDP
- 網路基本認知(2)--網路拓撲圖的規劃與設計
- 通過 Socket 實現 TCP 程式設計入門TCP程式設計
- 可程式設計網路卡晶片在滴滴雲網路的應用實踐程式設計晶片
- Java 網路程式設計(TCP程式設計 和 UDP程式設計)Java程式設計TCPUDP
- Go語言中的TCP/IP網路程式設計GoTCP程式設計
- Python 網路資料傳輸協議 TCP 程式設計Python協議TCP程式設計
- 001 Rust 網路程式設計,實現 TCP 服務端和客戶端程式Rust程式設計TCP服務端客戶端
- 基於TCP協議的Socket網路程式設計( )TCP協議程式設計
- 《Linux網路開發必學教程》8_應用協議設計與實現Linux協議
- 基於Java的Socket類Tcp網路程式設計實現實時聊天互動程式(一):QQ聊天介面的搭建JavaTCP程式設計
- socket程式設計實現tcp伺服器_C/C++程式設計TCP伺服器C++
- Linux Shell程式設計(2)Linux程式設計
- 網路程式設計中TCP與UDP程式設計TCPUDP
- java網路程式設計(TCP詳解)Java程式設計TCP
- 網路程式設計TCP/IP詳解程式設計TCP
- 程式設計師如何實現“網際網路+”01-程式設計師走向自由職業的 5 種常見方式程式設計師
- 設計Android應用程式架構的基本指南:MVP:第2部分Android架構MVP
- 【Linux網路程式設計-2】TcpServer類、TcpClient類Linux程式設計TCPServerclient
- 【Linux】 Linux網路程式設計Linux程式設計
- Linux C/C++程式設計中的多執行緒程式設計基本概念LinuxC++程式設計執行緒
- linux c網路網路程式設計面試題收集Linux程式設計面試題
- 基於java的網路招聘系統的設計與實現Java