Linux网络编程之聊天程序(TCP协议之fork进程)

实现了服务端和客户端之间的相互聊天,不收顺序限制,可以同时进行。

服务端: 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>

#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 = 7575;     /* 设置默认端口 */


    if (argv[3])
lisnum = atoi(argv[3]);  /* 监听队列大小 */
else
lisnum = 5;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)   /* 创建socket对象 */
    {
perror("socket");
exit(EXIT_FAILURE);
    }
    
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;               /* 地址协议 */
    my_addr.sin_port = htons(myport);           /* 地址端口 */  
    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("wait for connect\n");
    len = sizeof(struct sockaddr);
    if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) 
/* 阻塞等待连接,连接成功返回新的socket描述符,their_addr存储客户端的sockaddr 地址信息
{
        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);
   
if(-1==(pid=fork()))      /* 创建新进程 */
{
perror("fork");exit(EXIT_FAILURE);
}
else if( pid == 0)           /* 子进程用于发送消息 */
{
while (1) 
{
bzero(buf, MAXBUF + 1);
printf("input the message to send:");
fgets(buf, MAXBUF, stdin);
if (!strncasecmp(buf, "quit", 4)) 
{
printf("i will close the connect!\n");
break;
}
len = send(new_fd, buf, strlen(buf) - 1, 0);
  if (len < 0)
{
printf("message'%s' send failure!errno code is %d,errno message is '%s'\n",
buf, errno, strerror(errno));
break;
}
}
}
else                                          /* 父进程用于接收消息 */
{
while(1)
{
bzero(buf, MAXBUF + 1);
len = recv(new_fd, buf, MAXBUF, 0);
if (len > 0)
printf("message recv successful :'%s',%dByte recv\n",buf, len);
else if (len < 0)
{
printf("recv failure!errno code is %d,errno message is '%s'\n",
errno, strerror(errno));
break;
}
else
{
printf("the other one close quit\n");
break;
}
}
}
close(new_fd);
close(sockfd);
    return 0;
}


客户端程序: client.c
#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) {        /* 创建socket对象 */
perror("Socket");
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)   /* 对方IP地址 */
    {
perror(argv[1]); exit(errno);
    }
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))==-1)        /* 发起连接 */
    {
perror("Connect ");
exit(errno);
    }
    printf("server connected\n");

pid_t pid;
if(-1==(pid=fork()))                                     /* 创建新进程 */
{
perror("fork");exit(EXIT_FAILURE);
}
else if (pid==0)                              /* 子进程用于接收消息,不懂进程的自己去百度一下吧 */
{
while (1) 
{
bzero(buffer, MAXBUF + 1);
len = recv(sockfd, buffer, MAXBUF, 0);
if (len > 0)
printf("recv successful:'%s',%d byte recv\n",buffer, len);
else if(len < 0)
{
perror("recv");
break;
}
else
{
printf("the other one close ,quit\n");
break;
}
}
}
else                                   /* 父进程用于发送消息 */
{
while (1) 
{
bzero(buffer, MAXBUF + 1);
printf("pls send message to send:");
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) 
{
perror("send");
break;
}
}
}
    close(sockfd);
    return 0;
}

测试方法如下:
gcc server.c -o server
gcc client.c -o client
./server 172.16.148.114  8888       /* 一个终端下,172.16.148.114是我虚拟机的IP地址*/
./client 172.16.148.114  8888      /*另外 一个终端下 */


补充一个知识点:
int shutdown(int sockfd,int how);
shutdown可直接关闭描述符,不考虑描述符的参考数,可选择中止一个方向的连接
how的方式有三种分别是
SHUT_RD(0):关闭sockfd上的读功能,此选项将不允许sockfd进行读操作。
SHUT_WR(1):关闭sockfd的写功能,此选项将不允许sockfd进行写操作。
SHUT_RDWR(2):关闭sockfd的读写功能。

你可能感兴趣的:(Linux网络编程之聊天程序(TCP协议之fork进程))