本文主要用于記錄(因為有道雲容易丢失資料),代碼并不規範,所有的内容都寫在main()函數裡面了,主要目的是為了友善自己理清流程。
服務端的代碼:
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<signal.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "cs1.h"
void log_error(){
printf("errno = %s\n", strerror(errno));
}
void sig_handle(int sig){
printf("接收到了一個信号: %d\n", sig);
switch(sig){
case SIGPIPE:
printf("收到SIGPIPE...\n");
break;
}
}
int main(){
//定義變量
int server_fd;
int client_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;//用戶端
int client_addr_len;
int bind_res;
int listen_res;
int select_res;
fd_set fd_read_set;
fd_set temp_read_set;
fd_set fd_write_set;
fd_set temp_write_set;
int select_count = 1;
int fd_arr[1000];
int temp_fd;
int ioctl_res;
int read_len;
int write_len;
char read_buf[1024];
char* client_ip;
int client_port;
int write_res;
//設定信号處理函數
//對一個對端已經關閉的socket調用兩次write,
//第二次将會生成SIGPIPE信号, 該信号預設結束程序
struct sigaction sa;
sa.sa_handler = sig_handle;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGPIPE, &sa, NULL);
//初始化
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(IP);
//建立socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_fd == -1){
printf("socket()調用失敗...\n");
log_error();
exit(EXIT_FAILURE);
}
printf("server_fd = %d\n", server_fd);
fd_arr[0] = server_fd;
//bind
bind_res = bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(bind_res == -1){
printf("bind()調用失敗...\n");
log_error();
exit(EXIT_FAILURE);
}
//listen
listen_res = listen(server_fd, 5);
if(listen_res == -1){
printf("listen()調用失敗...\n");
log_error();
exit(EXIT_FAILURE);
}
//初始化fd_set
FD_ZERO(&fd_read_set);
FD_ZERO(&fd_write_set);
FD_SET(server_fd, &fd_read_set);
while(1){
temp_read_set = fd_read_set;
temp_write_set = fd_write_set;
printf("select()調用之前----------------------------------\n");
//select()每次調用之後都會改變傳進去的集合
//将準備好的fd留在集合裡面,将沒有準備好的從集合裡面删除
//這是很關鍵的一點
select_res = select(FD_SETSIZE, &temp_read_set,\
&temp_write_set, NULL, NULL);
if(select_res == -1){
printf("select()發生了錯誤\n");
log_error();
exit(EXIT_FAILURE);
}
printf("準備好了的fd個數 = %d\n", select_res);
printf("select_count = %d\n", select_count);
for(int i = 0; i < select_count; i++){
temp_fd = fd_arr[i];
printf("temp_fd = %d.......................\n", temp_fd);
//printf("server_fd = %d\n", server_fd);
if(temp_fd == server_fd){ //服務端準備好了
if(FD_ISSET(temp_fd, &temp_read_set)){
printf("服務端讀準備好了...\n");
client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd,\
(struct sockaddr*)&client_addr,&client_addr_len);
if(client_fd == -1){
printf("accept()調用失敗\n");
log_error();
continue;
}
if(select_count < 1000){
fd_arr[select_count] = client_fd;
select_count++;
FD_SET(client_fd, &fd_read_set);
FD_SET(client_fd, &fd_write_set);
//break;
}else{
printf("fd_arr已經滿了,不再接收\n");
}
}
}else{ //用戶端準備好了
if(FD_ISSET(temp_fd, &temp_read_set)){
printf("用戶端讀準備好了...\n");
ioctl_res = ioctl(temp_fd, FIONREAD, &read_len);
if(ioctl_res == -1){
printf("ioctl()調用發生錯誤\n");
log_error();
exit(EXIT_FAILURE);
}
printf("read_len = %d\n", read_len);
read_len = read_len > 1022 ? 1023 : read_len;
if(read_len > 0){
read(temp_fd, read_buf, read_len);
read_buf[read_len] = '\0';
printf("temp_fd = %d, read_buf = %s\n", temp_fd,\
read_buf);
}
}
//寫準備好了
if(FD_ISSET(temp_fd, &temp_write_set)){
printf("用戶端寫準備好了\n");
//client_ip = inet_ntoa(client_addr.sin_addr);
//client_port = ntohs(client_addr.sin_port);
client_ip = read_buf;
if(strlen(client_ip) == 0){
printf("要發送的長度為0\n");
continue;
}
write_res = write(temp_fd, client_ip, strlen(client_ip));
printf("write_res = %d\n", write_res);
if(write_res == -1){
printf("write()發生錯誤..\n");
log_error();
//可能是用戶端關閉了造成的
FD_CLR(temp_fd, &fd_write_set);
FD_CLR(temp_fd, &fd_read_set);
}
//write(temp_fd, &client_port, sizeof(client_port));
}
}
sleep(3);
}
}
return 0;
}
用戶端的代碼:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<errno.h>
#include<string.h>
#include "cs1.h"
int main(){
int sfd;
struct sockaddr_in server_addr;
char read_buf[1024];
int addr_len;
int co_res;
int ioctl_res;
int read_len;
//建立socket
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1){
printf("建立socket失敗\n");
strerror(errno);
exit(EXIT_FAILURE);
}
printf("sfd = %d\n", sfd);
//連接配接socket
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);//對port使用short
server_addr.sin_addr.s_addr = inet_addr(IP);
addr_len = sizeof(server_addr);
printf("addr_len = %d\n", addr_len);
co_res = connect(sfd, (struct sockaddr*)(&server_addr), addr_len);
if(co_res != 0){
printf("連接配接失敗\n");
close(sfd);
exit(EXIT_FAILURE);
}
printf("connect()調用傳回,且傳回值不等于0...\n");
while(1){
printf("循環開始----------------------------------\n");
//向socket裡面寫入資料
write(sfd, "a", 1);
ioctl_res = ioctl(sfd, FIONREAD, &read_len);
if(ioctl_res == -1){
printf("ioctl()調用失敗...\n");
exit(EXIT_FAILURE);
}
if(read_len == 0){
printf("read_len等于0...\n");
//exit(EXIT_FAILURE);
}
printf("read_len = %d \n", read_len);
read_len = read_len > 1022 ? 1023 : read_len;
if(read_len > 0){
read(sfd, read_buf, read_len);
read_buf[read_len] = '\0';
printf("用戶端讀取到的資料 = %s\n", read_buf);
}
printf("循環結束----------------------------------\n");
sleep(3);
}
return 0;
}