#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#include <semaphore.h>
#define SERVER_PORT 4000/*服务器端口号:4000*/
#define NUM_MAX_CLIENTS 10/*最多接受10个客户端发送消息*/
#define SEND_MAX_DATA_LENS 1024
#define RECV_MAX_DATA_LENS 1024
#define MAX_DATA_NUM 128
struct client_t/*client结构体,包含一个套接字的编号,发送线程和接受线程*/
{
int sockid[NUM_MAX_CLIENTS];
pthread_t send_tid[NUM_MAX_CLIENTS];
pthread_t recv_tid[NUM_MAX_CLIENTS];
};
struct client_t g_client;
int g_client_id = 0;
struct msg{
char data[MAX_DATA_NUM];
};
void *send_msg(void *arg);//接收数据线程函数
void *recv_msg(void *arg);//发送数据线程函数
int get_id(){
for(int i=0;i<NUM_MAX_CLIENTS;i++){
if(g_client.sockid[i]==-1)
return i;
}
return -1;
}
int main(int argc, char *argv[])
{
int sock_fd;
int current_client_id;
pthread_attr_t attr;/*线程的属性*/
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t sin_size;
int err;
int port_reuse = 1;
for(int i=0;i<NUM_MAX_CLIENTS;i++){
g_client.sockid[i]=-1;//初始化所有的套接字编号
}
/*创建分离线程*/
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/*创建套接字*/
if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("can not get a socket!\n");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
if((setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &port_reuse, sizeof(int))) == -1){
perror("addr port reuse error!\n");
exit(1);
}
/*捆绑socket描述符、服务器地址和端口号*/
if(bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){
perror("bind error\n");
exit(1);
}
/*监听端口*/
if(listen(sock_fd, NUM_MAX_CLIENTS) == -1){
perror("listen error\n");
exit(1);
}
printf("服务器监听端口%d...\n",SERVER_PORT);
/*等待客户端连接,每连接一个客户端,为这个客户端分别建立一个发送和接收线程*/
while(1){
sin_size = sizeof(struct sockaddr);
/*接收新的连接*/
g_client_id=get_id();
{
int a=accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
g_client.sockid[g_client_id] = a;
if(g_client.sockid[g_client_id] == -1){
perror("accept error");
}
current_client_id = g_client_id;
printf("新连接来自客户端[%d]:%s\n\n",current_client_id,inet_ntoa(client_addr.sin_addr));
/*创建接受线程*/
err = pthread_create(&g_client.recv_tid[current_client_id], &attr, recv_msg, (void *)¤t_client_id);
if(0 != err){
printf("can't create recv_msg thread!\n");
exit(1);
}
/*创建发送线程*/
err = pthread_create(&g_client.send_tid[current_client_id], &attr, send_msg, (void *)¤t_client_id);
if(0 != err){
printf("can't create send_msg thread!\n");
exit(1);
}
}
}
return 0;
}
/*接收线程*/
void *recv_msg(void *arg)
{
int client_id;
struct msg server_recv_msg;
struct timeval timeout;
fd_set recvfds;
int numbytes;
char buf[RECV_MAX_DATA_LENS];
client_id = *(int *)arg;
timeout.tv_sec = 100;//秒
timeout.tv_usec =0;//微秒
int flag=1;
while(flag){
FD_ZERO(&recvfds);
FD_SET(g_client.sockid[client_id], &recvfds);
switch(select(g_client.sockid[client_id] + 1, &recvfds, NULL, NULL, &timeout)){
case -1:
printf("Select error!\n");
flag=0;
break;
case 0:
printf("服务器没有任何输入信息,并且客户端%d也没有信息到来,关闭与该客户端的连接...\n",client_id);
close(g_client.sockid[client_id]);
g_client.sockid[client_id]=-1;
flag=0;
break;//超时
default:
if(FD_ISSET(g_client.sockid[client_id], &recvfds) > 0) {
if((numbytes = recv(g_client.sockid[client_id], buf, RECV_MAX_DATA_LENS, 0)) == -1){
perror("receive error\n");
close(g_client.sockid[client_id]);
exit(1);
}
if(0 == numbytes){ //若客户端关闭,一关掉相应的客户端的套接字,二,关掉相应的发送线程,三,关掉本线程
printf("client[%d] socket is closed!\n", client_id);
g_client_id=client_id;
close(g_client.sockid[client_id]);
g_client.sockid[client_id]=-1;
flag=0;
break;
}
else{
printf("接收来自客户端[%d]数据:%s", client_id, buf);
printf("长度:%d个字节\n\n",strlen(buf)-1);
}
}
}
}
}
/*发送线程*/
void *send_msg(void *arg)
{
struct msg server_send_msg;
int client_id;
char number[NUM_MAX_CLIENTS];
while(1){
memset(server_send_msg.data,'\0',sizeof(server_send_msg.data));
fgets(server_send_msg.data,sizeof(server_send_msg.data),stdin);
client_id = *(int *)arg;
printf("请输入要发送消息的客户端号:");
fgets(number,sizeof(number),stdin);
client_id=atoi(number);
if(send(g_client.sockid[client_id], (void *)&server_send_msg, sizeof(server_send_msg)-1, 0) == -1){
perror("send server message error!\n");
close(g_client.sockid[client_id]);
pthread_exit(NULL);
}
else
printf("长度是:%d\n\n",strlen(server_send_msg.data)-1);
}
}