基於TCP協議的回顯服務器,簡單的只有一個連接客戶端。
服務器流程:
1.創建文件描述符sock,並初始化 sockaddr_in ip地址和端口號
2.bind() 綁定文件描述符
3.accept() 阻塞等待客戶端連接,返回新的文件描述符 newsock
4.循環讀寫客戶端請求和響應
server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<arpa/inet.h>
//./server 0 8080
int main(int argc,char *argv[])
{
if(argc != 3)
{
printf("usage: ./client [ip] [port]");
return 1;
}
//創建文件描述符
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
printf("create socket error\n");
return 2;
}
struct sockaddr_in server_socket;
server_socket.sin_family = AF_INET;
server_socket.sin_port = htons(atoi(argv[2]));
server_socket.sin_addr.s_addr = inet_addr(argv[1]);
//綁定文件描述符,IP/PORT
if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0)
{
printf("bind error\n");
return 3;
}
printf("bind and listen success..\n");
struct sockaddr_in peer;
char buf[1024];
while(1)
{
//調用accept函數,阻塞等待客戶端連接,返回值是新的newsock
socklen_t len = sizeof(peer);
int new_sock = accept(sock,(struct sockaddr*)&peer,&len) ;
if(new_sock < 0)
{
printf("accept error\n");
return 5;
}
//循環讀寫客戶端得請求
while(1)
{
memset(buf,'\0',sizeof(buf));
if(read(new_sock,buf,sizeof(buf)) < 0)
{
printf("read error\n");
return 6;
}
printf("cient # %s\n",buf);
if(write(new_sock,buf,sizeof(buf))<0)
{
printf("write error\n");
return 7;
}
}
}
//記得關閉文件描述符
close(sock);
return 0;
}
客戶頓簡單流程:
1.創建文件描述符sock
2.調用connect()函數,請求連接服務器
3.連接成功,循環請求
client.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<arpa/inet.h>
// ./client 127.0.0.1 8080
int main(int argc,char *argv[])
{
if(argc != 3)
{
printf("usage: ./client [ip] [port]");
return 1;
}
//創建文件描述符sock
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
printf("create socket error\n");
return 2;
}
struct sockaddr_in client_socket;
client_socket.sin_family = AF_INET;
client_socket.sin_port = htons(atoi(argv[2]));
client_socket.sin_addr.s_addr = inet_addr(argv[1]);
//調用connect() 函數 請求和服務器連接(三次握手)
int ret = connect(sock,(struct sockaddr*)&client_socket,sizeof(client_socket));
if(ret < 0)
{
printf("connect failed...\n");
return 3;
}
printf("connect success..\n");
char buf[1024];
memset(buf,'\0',sizeof(buf));
//循環請求服務器,服務器響應
while(1)
{
printf("client:#");
fgets(buf,sizeof(buf),stdin);
socklen_t len = strlen(buf);
buf[len-1] = '\0';
write(sock,buf,sizeof(buf));
printf("pleas wait...\n");
read(sock,buf,sizeof(buf));
printf("server # : %s\n",buf);
}
close(sock);
return 0;
}
運行效果:
server:
client:
使用指令 netstat -nltp 指令來查看現在系統中有多少的基於TCP協議上的通信:
上面的代碼完成了我們想要的回顯功能,客戶端和服務器完成了數據交互。
當我們再啓動另一個客戶端時,再連接服務器,發現連接上了,但是卻無法完成數據交互。
服務器沒有響應。
看我們的代碼可以看到,我們調用accept後,程序就一直在read阻塞等待了,並不能再accept另一個文件描述符了。
我們可以怎麼處理這個問題呢。多進程,多線程可以解決。