曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4928|回复: 0
打印 上一主题 下一主题

简单聊天程序

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2010-4-5 14:26:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
程序说明
使用 TCP 实现简单聊天程序,这个程序的缺点是必须按照特定顺序操作,即一收一发或一发一收。

服务器端代码
#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>

#define MAXBUF 1024

int main (int argc, char *argv[])
{
    int pid;
    int sockfd, new_fd;
    socklen_t len;
    struct sockaddr_in my_addr, their_addr;
    unsigned int myport, lisnum;
    char buf[MAXBUF + 1];

    /*将命令行中指定的端口参数转换为整数*/
    if (argv[2])
        myport = atoi (argv[2]);
    else
        myport = 8888;    /*默认端口设置*/

    if (argv[3])
        lisnum = atoi(argv[3]);    /*监听队列大小*/
    else
        lisnum = 5;    /*如果无指定则默认设置*/

    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit (EXIT_FAILURE);
    }
   
    bzero (&my_addr, sizeof(my_addr));    /*清空地址结构*/

    my_addr.sin_family = AF_INET;    /*地址协议*/
    my_addr.sin_port = htons (myport);    /*地址端口*/

    /*将点分十进制字符串转换为网络顺序IP地址*/
    if (argv[1])
        my_addr.sin_addr.s_addr = inet_addr(argv[1]);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;    /*否则设置为本机任意地址*/

    if (bind (sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {       
        perror ("bind");
        exit (EXIT_FAILURE);
    }

    if (listen (sockfd, lisnum) == -1) {
        perror ("listen");
        exit (EXIT_FAILURE);
    }
    printf ("waiting for connect\n");

    len = sizeof (struct sockaddr);
    if ((new_fd = accept (sockfd, (struct sockaddr *) &their_addr, &len)) == -1) {
        perror ("accept");
        exit (EXIT_FAILURE);
    } else
        printf ("server: got connection from %s, port:%d, socket:%d\n",
                inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);

    while (1) {
        printf ("newfd = %d\n", new_fd);
        bzero (buf, MAXBUF + 1);
        printf ("input the message to send:");

        fgets (buf, MAXBUF, stdin);        /*接收终端输入消息*/
        if (!strncasecmp (buf, "quit", 4)) {
            printf ("close connection\n");    /*退出循环*/
            break;
        }
        len = send (new_fd, buf, strlen(buf) - 1, 0);    /*发送数据*/

        if (len > 0)
            printf ("message:%s\t send successfully, send %dbytes!\n", buf, len);
        else {
            printf ("message '%s' send failure!errno code is %d, errno message is '%s'\n", buf, errno,
                    strerror (errno));
            break;
        }
        bzero (buf, MAXBUF + 1);
        len = recv (new_fd, buf, MAXBUF, 0);    /*接收到消息*/

        if (len > 0)
            printf ("message recv successfully: '%s', %dbytes recv\n", buf, len);
        else {
            if (len < 0)
                printf ("recv failure! errno code is %d, errno message is '%s'\n", errno, strerror(errno));
            else
                printf ("the other one close quit\n");
           
            break;
        }
    }
    close (new_fd);
    close (sockfd);
    return (0);
}

客户端代码
#include <stdio.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>

#define MAXBUF 1024

int main (int argc, char **argv)
{
    int sockfd, len;
    struct sockaddr_in dest;
    char buffer[MAXBUF + 1];

    if (argc != 3) {
        printf ("error format, it must be:\n\t\t%s IP port\n", argv[0]);
        exit (EXIT_FAILURE);
    }

    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
        perror ("sock");
        exit (errno);
    }

    printf ("socket created\n");

    bzero (&dest, sizeof (dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons (atoi (argv[2]));    /*将命令行中的端口转换为整型然后再转换为网络字节顺序*/

    if (inet_aton (argv[1], (struct in_addr *)&dest.sin_addr.s_addr) == 0) {
        perror (argv[1]);
        exit (errno);
    }
   
    if (connect (sockfd, (struct sockaddr *)&dest, sizeof(dest)) == -1) {
        perror ("Connect ");
        exit (errno);
    }
    printf ("server connected\n");

    while (1) {
        bzero (buffer, MAXBUF + 1);
        len = recv (sockfd, buffer, MAXBUF, 0);
        if (len > 0)
            printf ("recv successfully:'%s', %d bytes recv\n", buffer, len);
        else {
            if (len < 0)
                printf ("send failure, errno code is %d, err message is '%s'\n", errno, strerror(errno));
            else
                printf ("the other one close, quit\n");

            break;
        }
        bzero (buffer, MAXBUF + 1);
        printf ("plz send message:");
        fgets (buffer, MAXBUF, stdin);
       
        if (!strncasecmp (buffer, "quit", 4)) {
            printf ("i will quit!\n");
            break;
        }
        len = send (sockfd, buffer, strlen(buffer) - 1, 0);
        if (len < 0) {
            printf ("message '%s' send failure, errno code is %d, errno message is '%s'\n", buffer, errno, strerror(errno));
            break;
        } else
            printf ("message:%s\tsend successfully, %d bytes send!\n", buffer, len);
        }

    close (sockfd);
    return (0);
}
说明
在服务器端,可以在命令行中指定端口,否则默认用 8888 。接着掉用 listen() 函数进行监听,不失败的话,就会用 accept() 函数阻塞式的一直等待客户端连接。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 16:25 , Processed in 0.078625 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表