Linxu下使用套接字编写一对一聊天功能

新增知识点

(1)fd_set的数据结构

select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄, 还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fe_set的内容,由此 来通知执行了select()的进程哪一socket或文件可读。(起到一个根据描述符通知要不要干某事情的作用)  

fd_set set;  

FD_ZERO(&set);/*将set清零使集合中不含任何fd*/  

FD_SET(fd,&set); /*将fd加入set集合*/ 

FD_CLR(fd,&set); /*将fd从set集合中清除*/  

FD_ISSET(fd,&set); /*测试fd是否在set集合中*/要是判断出其中有描述符则进行相应的处理

IfFD_ISSET(fd,&set))//进行判断,要是有这个事情,则执行if语句

select函数 系统提供了select函数实实现多路复用输入/输出模型。原型

   #include <sys/time.h>

   #include <unistd.h>

   int select(int maxfd, fd_set *rdset, fd_set*wrset, fd_set *exset, struct timeval *timeout);

   参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合。可写文件描述符的集合。及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内, 需要监视的描述符没有事件发生则函数返回,返回值为0。

(2)键盘输入读取,数据清空

fgets(buf, MAXBUF,stdin);从输入中读取字符到buf

bzero(buf, MAXBUF);清空buf

memset(buf,0,sizeof(buf));清空buf

fflush(stdin);清空输入缓冲区

(3)运行服务器程序的时候出现端口被占用

步骤一:查看端口是否被占用 输入命令:

lsof–i : 《端口号》   要是改端口被那个程序占用或者绑定,这可以看到相关的信息,要是没有被使用,这没有任何信息。

键入 netstat –apu|grep 《端口号》也可以查看

步骤二: 步骤一可以知道,那些进程在使用这个端口,输入命令:ps –L,可以查看有那个进程在运行,找到相应的进程,ID

步骤三:将进程杀死。Kill -9 PID,步骤二中知道的进程。


test_server.c代码:

//

#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 <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>

#define PORT 3492
#define MAXBUF 1024
#define MAX_CONN_NM 5
#define Server_IP  "127.0.0.1"

 
int main(void)
{
     int sockfd, client_fd,sendbytes,len;
     struct sockaddr_in server_addr,client_addr;
     char buf[MAXBUF];
     int sin_size, recvbytes;
     fd_set rfds;
     int retval, maxfd = -1;
 
     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
         perror("socket");
         exit(1);
     }
    /*初始化服务器的地址结构*/
    bzero(&server_addr, sizeof(server_addr));
     /*使用internet协议族*/
    server_addr.sin_family = AF_INET;
      /*使用制定的端口*/
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr(Server_IP);//INADDR_ANY;//
    memset(server_addr.sin_zero,0,8);

    int i = 1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
   
     if (bind(sockfd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr))
         == -1) {
         perror("bind");
         exit(1);
     }
     printf("Blind success");
     if (listen(sockfd, MAX_CONN_NM) == -1) {
         perror("listen");
         exit(1);
     }
 

     printf("Listening...................\n");

    while(1)
    {
          if ((client_fd =accept(sockfd, (struct sockaddr *) &client_addr,&sin_size)) == -1)
           {  //accept函数返回一个新的socket,这个socket(client_fd)用于同连接到的客户的通信
             perror("accept");
             exit(errno);
           }
         /* 开始处理每个新连接上的数据收发 */
         printf (" Read to char\n");
           /* 接收客户端的消息 */
         while(1)
         {

             /* 把集合清空 */
             FD_ZERO(&rfds);
             /* 把标准输入句柄0加入到集合中 */
             FD_SET(0, &rfds);
             maxfd = 0;
             /* 把当前连接句柄new_fd加入到集合中 */
             FD_SET(client_fd, &rfds);
             if (client_fd > maxfd)
                 maxfd = client_fd+1;
             retval = select(maxfd, &rfds, (fd_set *)NULL, (fd_set *)NULL, (struct timeval*)NULL); //开始监听那些文件描述符出于可读状态
             if (retval == -1)
            {
                printf("Chuxuancuowu%s", strerror(errno));
                break;
            }
             else if (retval == 0)
            {
             continue;
            }
            else
            {
                    if (FD_ISSET(0, &rfds))
                    {
                        memset(buf,0,sizeof(buf));
                        fgets(buf, MAXBUF, stdin);
                        if (!strncasecmp(buf, "quit", 4)) //在buf查找quit要是有一样的函数strncasecmp返回0;
                        {
                             printf("Qing qiu tui chu lianjie");
                             break;
                        }
                        sendbytes = send(client_fd, buf, strlen(buf) - 1, 0);
                        if (sendbytes < 0)
                         {
                             printf
                            ("xiaoxi'%s'fasongshibai..cuowudaimashi%d,cuowuxiaoshishi'%s' ",
                            buf, errno, strerror(errno));
                           }
                        else
                        {
                            printf("Send Mecessage:%s ",buf);
                        }
                    }
                    /* 当前连接的socket上有消息(客户端)到来则接收对方发过来的消息并显示 */
                    if(FD_ISSET(client_fd, &rfds))
                    {
                        bzero(buf, MAXBUF );
                        len = recv(client_fd, buf, MAXBUF, 0);
                        if(len > 0)
                        {
                             printf("Receive message:%s\n", buf);
                        }
                        else
                        {
                            perror("Receive failed!!");
                            break;
                        }
                    }
                
                   
             }

            }
         close(client_fd);
         close(sockfd);
         return 0;
}
}

//

teat_client.c代码

//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <resolv.h>
#include <netdb.h>

#define PORT 3492
#define MAXBUF 1024
#define MAX_CONN_NM 5
#define Server_IP  "127.0.0.1"


int main(int argc, char **argv)
{
      int sockfd, sendbytes,len;
     struct hostent *host;
     char buf[MAXBUF];
     struct sockaddr_in serv_addr;
     struct sockaddr_in dest;
      fd_set rfds;
    int retval, maxfd = -1;
   
     if (argc < 1) {
         printf
         ("Canshucuowu",
              argv[0], argv[0]);
         exit(0);
     }
//     if((host = gethostbyname(argv[1]) )== NULL)
//     {
//        perror("gethostbyname");
//        exit(1);
//     }
    
     memset(buf,0,sizeof(buf));
     //fgets(buf, MAXBUF, stdin); //sprintf(buf,"%s",argv[1]);
     /* 创建一个 socket 用于 tcp 通信 */
     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
         perror("Socket");
         exit(1);
     }


     /* 初始化服务器端(对方)的地址和端口信息 */
 
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons(PORT);
     serv_addr.sin_addr.s_addr = inet_addr(Server_IP); // serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
      memset(serv_addr.sin_zero,0,8);
 
     /* 连接服务器 */
     if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) {
         perror("Connect ");
         exit(1);
     }
     while(1)
     {  
         /* 把集合清空 */
        FD_ZERO(&rfds);
         /* 把标准输入句柄0加入到集合中 */
        FD_SET(0, &rfds);
        maxfd = 0;
         /* 把当前连接句柄sockfd加入到集合中 */
        FD_SET(sockfd, &rfds);
        if (sockfd > maxfd)
            maxfd = sockfd+1;
          
        retval = select(maxfd, &rfds, (fd_set *)NULL, (fd_set *)NULL, (struct timeval*)NULL); //开始监听那些文件描述符出于可读状态
        if (retval == -1)
        {
             printf("Chuxuancuowu%s", strerror(errno));
             break;
        } else if (retval == 0)
        {
             continue;
        }
        else
        {
            if(FD_ISSET(sockfd, &rfds))
            {
                /* 连接的socket上有消息到来则接收对方发过来的消息并显示 */
                memset(buf,0,sizeof(buf));
                len = recv(sockfd, buf, MAXBUF, 0);
                if(len > 0)
                {
                    printf("Receive message: %s\n", buf);
                }
                else
                {
                    perror("Receive failed!!");
                    break;
                }
            }
            if(FD_ISSET(0, &rfds))
            {
                /* 用户按键了,则读取用户输入的内容发送出去 */
                memset(buf,0,sizeof(buf));
                fgets(buf, MAXBUF, stdin);
                if (!strncasecmp(buf, "quit", 4)) //在buf查找quit要是有一样的函数strncasecmp返回0;
                {
                     printf("Qing qiu tui chu lianjie");
                     break;
                 }
                sendbytes = send(sockfd, buf, strlen(buf) - 1, 0);
                if (sendbytes < 0)
                {
                     printf
                  ("xiaoxi'%s'fasongshibai..cuowudaimashi%d,cuowuxiaoshishi'%s' ",
                          buf, errno, strerror(errno));
                 } else
                 {
                     printf("Send Mecessage:%s ",buf);
                      
                 }
                    
            }
        }
      }

     /* 关闭连接 */
     close(sockfd);
     return 0;
 }

 

在程序中已经制定了连接的iP地址,127.0.0.1,任何计算机可以通过该ip与本机进行连接。要修改IP只要在宏定义上修改即可。

编译上面两个文件,运行及可。

首先要运行服务器程序,然后运行客户端程序。接下来就可以随便发送了,键盘输入“quit”结束通话!

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值