需求:实现一对一通信
server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>
#include "base.h"
#define LISTENQ 2 //最大监听队列
#define PORT 5000 //监听端口
#define MAXFD 2 //最大的在线用户数量
static int maxi = 0; //maxi表示当前client数组中最大的用户的i值
typedef struct sockNode SOCKNODE;
struct sockNode
{
char name[128]; // 存储名字
int fd; // 存储套接字
struct sockNode *pNext;
};
SOCKNODE sockList; // 全局的套接字链表
void initList(SOCKNODE *sockList)
{
sockList = (SOCKNODE *)malloc(sizeof(SOCKNODE));
sockList->pNext = NULL;
sockList->fd = 0;
}
void insertList(SOCKNODE *sockList, int new_fd) //头部插入链表
{
int flags;
SOCKNODE *p = sockList;
SOCKNODE *sockNew = (SOCKNODE *)malloc(sizeof(SOCKNODE));
// 设置非阻塞方式
flags = fcntl(new_fd, F_GETFL, 0);
fcntl(new_fd, F_SETFL, flags | O_NONBLOCK);
sockNew->fd = new_fd;
sockNew->pNext = NULL;
while(p->pNext != NULL)
{
p = p->pNext;
}
p->pNext = sockNew;
}
void transmit(int fd, message mess)
{
// char sendBuf[2048];
SOCKNODE *sock = &sockList;
sock = sock->pNext; // 第一个节点
/* memset(sendBuf, 0, sizeof(sendBuf));
memcpy(sendBuf, sock->name, sizeof(sock->name));
strcat(sendBuf, " : ");
strcat(sendBuf, mess->buffer);*/
while(sock->fd != fd || sock->pNext != NULL) //相邻
{
if(sock->fd == fd && sock->pNext != NULL) // 满足while第一个条件,跳过,第二条件,执行
sock = sock->pNext;
mess.sig_event = SIG_TRASMIT_MESSAGE;
send(sock->fd, (char *)&mess, sizeof(mess),0);
if(sock->pNext == NULL)// 到达末尾
break;
else
sock = sock->pNext;
}
}
void recvandsend(void) //监听转发线程入口函数
{
int index=0;
int nbytes=0;
char mess_buff[2048];
message mess;
int len;
int outindex=0;
printf("receive socket and return message!\n");
while(1)
{
SOCKNODE *sock = &sockList;
while(sock->pNext != NULL)
{
sock = sock->pNext;
nbytes = 0;
memset(mess_buff, 0, sizeof(mess_buff));
nbytes = recv(sock->fd, mess_buff, sizeof(mess_buff),0);
if(nbytes > 0) // 在某个套接字有消息进来
{
memcpy(&mess, mess_buff, sizeof(mess_buff));
if(mess.sig_event == SIG_CLIENT_SET_NAME)
{
memcpy(sock->name, mess.buffer, strlen(mess.buffer)); // 将昵称保存到节点中
printf("client [%d] name :%s\n", sock->fd, sock->name);
continue;
}
if(mess.sig_event == SIG_TRASMIT_MESSAGE)
{
printf("receive [%s] message [%s]\n", sock->name, mess.buffer);
transmit(sock->fd, mess); // 消息转发
continue;
}
}
}
}
pthread_exit(NULL);
exit(1);
}
int closeConnection(int sockfd)
{
char buffer[1024];
memset(buffer, 0 ,sizeof(buffer));
strncpy(buffer, "close", sizeof("close"));
if(write(sockfd, buffer, sizeof(buffer)) == -1)
return 1;
else
return 0;
}
int connectSucceeddMess(int sockfd)
{
message mess;
int sendBytes;
memcpy(mess.buffer, "SERVER : welecome to this chat room!", sizeof("SERVER : welecome to this chat room!"));
mess.sig_event = SIG_CLIENT_CONNECT_SUCCEED;
printf("%d socked connected succeed , return message : [%s]\n", sockfd, mess.buffer);
sendBytes = send(sockfd, (char *)&mess, sizeof(mess), 0);
printf("send bytes = [%d]\n", sendBytes);
if(sendBytes == -1 || sendBytes == 0)
return 1;
else
return 0;
}
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
int sockfd, new_fd;
int thr_id; /* thread ID for the newly createdthread */
pthread_t p_thread; /* thread's structure */
SOCKNODE *sockNew;
char buffer[1024];
int nbytes=0;
int flags;
initList(&sockList); // 初始化套接字链表
if(argc != 1)
{
fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);
exit(1);
}
/* 服务器端开始建立 socket 描述符 */
if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));
exit(1);
}
/* 服务器端填充 sockaddr 结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
/* 捆绑 sockfd 描述符 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Binderror:%s\n\a",strerror(errno));
exit(1);
}
printf("Server Port : %d ... ...\n",PORT);
/* 监听 sockfd 描述符 */
if(listen(sockfd,LISTENQ)==-1)
{
fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));
exit(1);
}
thr_id = pthread_create(&p_thread, NULL, recvandsend, NULL);
while(1)
{
// 服务器阻塞,直到客户程序建立连接
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size);
if(maxi >= MAXFD)
{
printf("will colse socket %d!\n",new_fd);
if((new_fd != -1) && (closeConnection(new_fd) == 0))
{
close(new_fd);
printf("close %d connection success\n",new_fd);
}
}
else
{
if(new_fd == -1)
{
printf("socket Error!\n");
exit(1);
}
else
{
if(!connectSucceeddMess(new_fd))
{
insertList(&sockList, new_fd); // 新套接字插入到链表中
maxi = maxi + 1;
printf("add %d to list succeed!\n", new_fd);
}
}
}
}
close(sockfd);
exit(0);
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <pthread.h>
#include "base.h"
#define TRUE 1
#define PORT 5000
static int sockfd;
static int set_name_falg = 1;
char name[100];
void closeClient()
{
char mes[2048];
int re;
recv(sockfd, mes, sizeof(mes), 0);
re = strncmp(mes, "close", sizeof("close"));
printf("%s\n", mes);
if(re == 0)
{
printf("will colse socke, and exit client!\n");
exit(1);
}
}
void* recvfromserver() //接受服务器消息线程入口函数
{
message mess;
int nbytes=0;
int re;
char mess_buf[2048];
printf("ready to receive message!\n");
while(1)
{
memset(mess_buf, 0, sizeof(mess_buf));
nbytes = recv(sockfd, mess_buf, sizeof(mess_buf), 0);
if(nbytes > 0 )
printf("recv bytes : [%d]\n", nbytes);
memcpy(&mess, mess_buf, sizeof(mess_buf));
if(mess.sig_event == SIG_SET_NAME_SUCCEED)
printf("set name succeed!\n");
if(mess.sig_event == SIG_CLIENT_CONNECT_SUCCEED)
{
printf("connected succeed!, \nreceive message from server :[%s]\n", mess.buffer);
set_name_falg = 0; // 连接成功后,设置称呼
}
if(mess.sig_event == SIG_TRASMIT_MESSAGE)
{
printf("get transmit message , content : [%s]\n",mess.buffer);
}
}
pthread_exit(NULL);
return NULL;
}
void logOut(int sockfd)
{
char mes[1024];
memset(mes, 0, sizeof(mes));
strncpy(mes, "client %d will close!", sizeof("client %d will close!"));
if(write(sockfd, mes, sizeof(mes)) == -1)
printf("close client %d succeed!\n", sockfd);
else
printf("close client %d failed!\n", sockfd);
}
/* 设置客户端名称*/
int set_name()
{
int sendBytes;
message mess;
printf("Set Your Name : ");
scanf("%s",name);
memset(&mess, 0, sizeof(mess));
memcpy(mess.buffer, name, strlen(name));
mess.sig_event = SIG_CLIENT_SET_NAME; //设置昵称事件号
printf("name is [%s]\n",mess.buffer);
sendBytes = send(sockfd, (char *)&mess, sizeof(mess), 0);
printf("send message Bytes : [%d]\n", sendBytes);
if(sendBytes == -1 || sendBytes == 0)
return 1;
else
return 0;
}
int sendMessage(char *buffer, int sig_type)
{
int sendBytes;
message mess;
memset(&mess, 0, sizeof(mess));
memcpy(mess.buffer, buffer, strlen(buffer));
mess.sig_event = sig_type; //设置昵称事件号
printf("send buffer is [%s]\n",mess.buffer);
sendBytes = send(sockfd, (char *)&mess, sizeof(mess), 0);
printf("send message Bytes : [%d]\n", sendBytes);
if(sendBytes == -1 || sendBytes == 0)
return 1;
else
return 0;
}
int main(int argc, char *argv[])
{
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber,nbytes;
char strhost[32];
int thr_id; /* thread ID for the newly createdthread */
pthread_t p_thread; // thread's structure
message mess;
if(argc!=1)
{
fprintf(stderr,"Usage:%s\a\n",argv[0]);
exit(1);
}
snprintf(strhost, 32, "%s", "10.47.181.159");
printf("The Server IP Address : [%s]", strhost);
if((host = gethostbyname(strhost)) == NULL)
{
fprintf(stderr,"Gethostnameerror\n");
exit(1);
}
/* 客户程序开始建立 sockfd 描述符 */
printf("Connection ... ...\n");
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
fprintf(stderr,"SocketError:%s\a\n",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr=*((struct in_addr *)host->h_addr);
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));
exit(1);
}
sleep(1);
thr_id = pthread_create(&p_thread, NULL, recvfromserver, NULL);
sleep(1);
printf("\nNOTICE: Press Quit or q or Q disconnect server!\n\n");
while(1)
{
if(set_name_falg == 0)
{
printf("Set Your Name : ");
gets(name);
sendMessage(name, SIG_CLIENT_SET_NAME);
set_name_falg = 1;
continue;;
}
printf("Input message : ");
memset(&buffer, 0, sizeof(buffer));
gets(buffer);
if(sendMessage(buffer, SIG_TRASMIT_MESSAGE) == 0)
{
printf("send successed!\n");
}
/*memcpy(mess.buffer, buffer, sizeof(buffer));
mess.sig_event = SIG_TRASMIT_MESSAGE;
printf("[%s] send message : [%s]\n", name, mess.buffer);
if((send(sockfd, (char *)&mess, sizeof(mess), 0)) == -1)
{
fprintf(stderr,"WriteError:%s\n",strerror(errno));
exit(1);
}*/
if(strcmp(buffer,"Quit")==0 || strcmp(buffer,"q")==0 || strcmp(buffer,"Q")==0)
{
logOut(sockfd);
break;
}
//closeClient(); //如果服务端的已经达到最大连接数,则拒绝连接,退出客户?
}
close(sockfd);
exit(0);
}