UCsocket 編程,簡單聊天室實現

/*
   TCP聊天室 客戶端
   */
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<netinet/in.h>
//一些準備工作
char* IP = "172.30.11.104";//127.0.0.1 本機地址,回送地址,用於網絡軟件測試 或本機通信
short PORT = 10222; // 端口
typedef struct sockaddr SA; //用做類型轉換
int sockfd= 0;
char name[20] = {};
//1 啓動客戶端,連接服務器
void init()
{
 printf("聊天室客戶端開始啓動。。\n");
 sockfd = socket(PF_INET,SOCK_STREAM,0);
 struct sockaddr_in addr;
 addr.sin_family = PF_INET;
 addr.sin_port = htons(PORT);
 addr.sin_family.s_addr = inet_addr(IP);
 //連接
 if(connect(sockfd,(SA*)&addr,sizeof(addr)) ==-1)
 {
  perror("無法連接服務器");
  printf("客戶端啓動失敗\n");
  exit(-1);
 }
 printf("客戶端啓動成功\n");
}
//2 開始通信
void start()
{
 //主要是用來發送消息
 //發消息之前,啓動一個線程 用來接收消息
 pthread_t pid;
 void* recv_thread(void* );
 pthread_create(&pid,0,recv_thread,0);
 while(1)
 {
  char buf[100] = {};
  scanf("%s",buf);//讀取客戶的輸入
  char msg[200] = {};
  sprintf(msg,"%s 說:%s",name,buf);
  send(sockfd,msg,strlen(msg),0);
 }
}
//線程函數 ,用來接收消息
void* recv_thread(void* p)
{
 char buf[200] = {};
 if(recv(sockfd,buf,sizeof(buf),0)<=0)
 {
  return ; //結束線程
 }
 printf("%s\n",buf);
}
void sig_close(int signo)
{//關閉客戶端socket
 close(sockfd);
 exit(0);
}
int main()
{
 signal(SIGINT,sig_close);
 printf("請輸入暱稱:\n");
 scanf("%s",name);
 init(); //啓動客戶端 連接到服務器
 send(sockfd,name,strlen(name),0);
 start();


}

 

/*
   TCP聊天室服務器
   */
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<netinet/in.h>
//一些準備工作
char* IP = "172.30.11.104";//127.0.0.1 本機地址,回送地址,用於網絡軟件測試 或本機通信
short PORT = 10222; // 端口
typedef struct sockaddr SA; //用做類型轉換
struct client
{
 char name[20];//記錄客戶端的暱稱
 int fds; //客戶端的socket描述符
};
struct client c[100] =  {0};//記錄客戶端的結構體數組 最多記錄了100個
int size = 0; //記錄客戶端的個數,也可以用來遍歷客戶端結構體
int sockfd = 0; //服務器的sockt
//1 初始化服務器的網絡,創建socket
void init()
{
 printf("聊天室服務器開始啓動……\n");
 sockfd = socket(PF_INET,SOCK_STREAM,0);
 if(sockfd == -1) perror("socket創建失敗,服務器啓動失敗"),exit(-1);
 struct sockaddr_in addr;
 addr.sin_family = PF_INET;
 addr.sin_port = htons(PORT);
 addr.sin_addr.s_addr = inet_addr(IP);
 if(bind(sockfd,(SA*)&addr,sizeof(addr))==-1)
 {
  perror("綁定失敗");
  printf("服務器啓動失敗\n");
  exit(-1);
 }
 printf("綁定成功\n");
 if(listen(sockfd,100) == -1)
 {
  perror("設置監聽失敗");
  printf("服務器啓動失敗\n");
  exit(-1);
 }
 printf("設置監聽成功\n");
 //等待客戶端連接到另一個函數中
 printf("初始化服務器成功\n");
}
/*
  輔助函數,用來分發消息
 */
void sendMsgToAll(char* msg)
{
 int i = 0;
 for( i = 0;i<size;i++)
 {
  printf("sendto %d\n",c[i].fds);
  send(c[i].fds,msg,strlen(msg),0);
 }
}

//線程函數,用來接收客戶端發來的消息,並且把消息發送給所有客戶端
void* service_thread(void* p)
{
 int fd = *(int*)p; //拿到客戶端的socket描述符
 printf("pthread = %d",fd); //線程對應客戶端
 //保留客戶端的信息
 c[size].fds = fd;
 char name[20] = {};
 if(recv(fd,name,sizeof(name),0)>0) //接收暱稱
 {
  strcpy(c[size].name,name);
 }
 size++;
 //先羣發一條消息,表示歡迎 也可以通知其他客戶端有人連接了 進入聊天室
 char tishi[100];
 sprintf(tishi,"熱烈歡迎%s登陸聊天室。。",name);
 //羣發消息
 sendMsgToAll(tishi);
 //通信部分,收發消息
 while(1)
 {
  char buf[200] = {};
  if(recv(fd,buf,sizeof(buf),0) == 0)
  {
   printf("fd = %d quit\n",fd);
   //有客戶端斷開
   int i;
   char name[20] = {};
   for(i= 0;i<size;i++)
   {
    if(c[i].fds == fd)
    {
     strcpy(name,c[i].name);
     c[i].fds = c[size-1].fds;
     strcpy(c[i].name,c[size-1].name);
    }
   }
   size--;
   printf("quit->fd=%d\n",fd);
   char msg[100] = {};
   sprintf(msg,"歡送 %s 離開聊天室,再見\n",name);
   sendMsgToAll(msg);
   close(fd);
   return ; //客戶端退出  結束線程
  }
  sendMsgToAll(buf); //成功接收到消息,就直接所有的客戶端
 }
}

//等待客戶端連接,啓動服務器服務
void service()
{
 printf("服務器開始服務\n");
 while(1)
 {
  struct sockaddr_in fromaddr; //存儲客戶端的通信地址
  socklen_t len = sizeof(fromaddr);
  int fd = accept(sockfd,(SA*)&fromaddr,&len);
  if(fd == -1)
  {
   printf("客戶端連接出錯\n");
   continue;
  }
  //如果客戶成功連接
  //開啓線程,爲該客戶端進行服務
  printf("fd =%d\n",fd);
  pthread_t pid;
  pthread_create(&pid,0,service_thread,&fd);
 }
}
void sig_close(int signo)
{ //關閉socket
 int i = 0;
 for(;i<size;i++)
 {
  if(c[i].fds!=0)
   close(c[i].fds);
 }
 close(sockfd);//服務器的socket;
 printf("服務器已經關閉\n");
 exit(0);

}
int main()
{
 signal(SIGINT,sig_close);//做好善後工作
 init();
 service();
 return 0;
}

 

 

 

 

發佈了72 篇原創文章 · 獲贊 6 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章