分为两个独立的程序
编译前先确定自己服务器的地址,比如想要在自己的ubuntu下运行,先ip addr获取自己的ip地址,修改chat_server.c,chat_client.c里面的ip地址为自己的ip地址
服务端chat_server.c
编译: gcc chat_server.c -o server
运行: ./server
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <signal.h>
#define MAX_USER 500
#define MAX_MSG_LEN 1024
#define MAX_IO_RETRY_TIMES 5
int server_fd;
int user_cnt = 0;
int user_fds[MAX_USER];
char msg_buffer[MAX_MSG_LEN];
void down()
{
int i;
for(i = 0; i < user_cnt; i++)
{
shutdown(user_fds[i], SHUT_RDWR);
close(user_fds[i]);
user_fds[i] = 0;
}
shutdown(server_fd, SHUT_RDWR);
close(server_fd);
server_fd = 0;
}
int go_on = 1;
void sig_handler(int signal)
{
go_on = 0;
}
int my_safe_read(int fd)
{
int ret;
int i;
for(i = 0; i < MAX_IO_RETRY_TIMES; i++)
{
errno = 0;
int ret = read(fd, msg_buffer, MAX_MSG_LEN);
if(ret < 0)
{
if(EAGAIN == errno || EWOULDBLOCK == errno)
{
printf("Safe read [%d] cnt\n", i + 1);
continue;
}
else
{
return ret;
}
}
else if(0 == ret)
{
return 0;
}
else
{
return ret;
}
}
return ret;
}
int my_safe_write(int fd)
{
write(fd, msg_buffer, MAX_MSG_LEN);
}
int main(int argc, char *argv[])
{
signal(SIGINT, sig_handler);
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == server_fd)
{
printf("socket err\n");
return -1;
}
printf("socket ok\n");
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
unsigned short portnum = 0x8888;
if(argc >= 2)
{
int port = atoi(argv[1]);
if(port > 20000)
{
portnum = port;
}
}
printf("port = %d\n", portnum);
server_addr.sin_port = portnum;
if(-1 == bind(server_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
{
printf("bind err\n");
return -1;
}
printf("bind ok\n");
if(-1 == listen(server_fd, MAX_USER))
{
printf("listen err\n");
return -1;
}
printf("listen ok\n");
int i;
fd_set fds;
struct timeval tv;
while(go_on)
{
FD_ZERO(&fds);
FD_SET(server_fd, &fds);
for(i = 0; i < user_cnt; i++)
{
printf("-%d\n", user_fds[i]);
if(user_fds[i])
{
FD_SET(user_fds[i], &fds);
}
}
int fd_cnt_to_selected = 0;
for(i = 0; i < user_cnt; i++)
{
if(user_fds[i] > fd_cnt_to_selected)
{
fd_cnt_to_selected = user_fds[i];
}
}
fd_cnt_to_selected = (0 == user_cnt)? (server_fd + 1) : (fd_cnt_to_selected + 1);
tv.tv_sec = 2;
tv.tv_usec = 0;
int ret = select(fd_cnt_to_selected, &fds, 0, 0, &tv);
if(ret < 0)
{
printf("select err\n");
break;
}
else if(0 == ret)
{
continue;
}
struct sockaddr_in client_addr;
for(i = 0; i < user_cnt; i++)
{
if(FD_ISSET(user_fds[i], &fds))
{
bzero(msg_buffer, MAX_MSG_LEN);
int ret = my_safe_read(user_fds[i]);
if(ret <= 0)
{
int connection_state = 1;
int len_of_int = sizeof(int);
getsockopt(user_fds[i], IPPROTO_TCP, SO_KEEPALIVE, (void*)&connection_state, &len_of_int);
printf("connection_state = %s\n", (0 == connection_state)? "break" : "alive");
if(0 == connection_state)
{
close(user_fds[i]);
FD_CLR(user_fds[i], &fds);
if(user_cnt - 1 == i)
{
user_cnt = user_cnt - 1;
user_fds[i] = 0;
}
else
{
int j;
for(j = i; j < user_cnt; j++)
{
user_fds[j] = user_fds[j+1];
}
user_fds[j] = 0;
user_cnt = user_cnt -1;
}
}
}
else
{
printf("receive[%s]\n", msg_buffer);
int j;
for(j = 0; j < user_cnt; j++)
{
if(j == i)
{
continue;
}
my_safe_write(user_fds[j]);
}
}
}
}
if(FD_ISSET(server_fd, &fds))
{
int sin_size = sizeof(struct sockaddr);
user_fds[user_cnt] = accept(server_fd, (struct sockaddr *)(&client_addr), &sin_size);
if(-1 == user_fds[user_cnt])
{
printf("accept err\n");
return -1;
}
printf("accept ok!\n");
printf("user_fds[user_cnt] = %d\n", user_fds[user_cnt]);
user_cnt++;
}
}
down();
return 0;
}
客户端chat_client.c
编译: gcc chat_client -lpthread -o chat_client
运行: 服务端先运行起来后,再启动客户端,可以在多态机器上启多个客户端,互相聊天
./chat_client
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <pwd.h>
#include <signal.h>
int cfd = 0;
struct passwd *pwd;
void sig_handler(int signal)
{
char bye_msg[1024] = { 0 };
sprintf(bye_msg, "WARNING------>User[%s] have go, he said all is 'SB'! Oh, what the fuck!", pwd->pw_name);
write(cfd, bye_msg, 1024);
shutdown(cfd, SHUT_RDWR);
close(cfd);
cfd = 0;
exit(-1);
}
void* f(void* t)
{
struct timeval tv;
fd_set fds;
while(1)
{
tv.tv_sec = 0;
tv.tv_usec = 100;
FD_ZERO(&fds);
FD_SET(cfd, &fds);
int r = select(cfd + 1, &fds, 0, 0, &tv);
if(r<0)
{
printf("select err\n");
}
else if(r==0)
{
}
char buf[1024*10] = { 0 };
int n = read(cfd, buf, 1024*10);
if(buf[0] != 0)
printf("%s\n", buf);
}
}
int main(int argc, char * argv[])
{
signal(SIGINT, sig_handler);
pwd = getpwuid(getuid());
int recbytes;
int sin_size;
char buffer[1024] ={0};
struct sockaddr_in s_add, c_add;
unsigned short portnum =0x8888;
if(argc >= 2)
{
int port = atoi(argv[1]);
if(port > 20000)
portnum = port;
}
printf("port = %d\n", portnum);
cfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == cfd)
{
printf("socket err\n");
return -1;
}
//printf("socket ok\n");
bzero(&s_add, sizeof(struct sockaddr_in));
s_add.sin_family = AF_INET;
s_add.sin_addr.s_addr = inet_addr("192.168.60.104");
s_add.sin_port = htons(portnum);
if(-1 == connect(cfd, (struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
{
printf("connect err\n");
return -1;
}
char personal_info[128] = { 0 };
sprintf(personal_info, "DouBi[%s] is comming!!!HaHaaa^-^", pwd->pw_name);
write(cfd, personal_info, 128);
//printf("connect ok\n");
pthread_t th;
int rr = pthread_create((pthread_t *)&th, NULL, f, NULL);
while(1)
{
//printf("enter what you want to say:_\n");
char b[10240] = { 0 };
sprintf(b, "[%s]: ", pwd->pw_name);
gets(b + strlen(b));
//printf("b = %s\n", b);
if(-1 == (recbytes = write(cfd, b, 1024*10)))
{
printf("send data err\n");
return -1;
}
//printf("send ok\n");
}
//close(cfd);
// sleep(100);
return 0;
}