实现了服务端和客户端之间的相互聊天,不收顺序限制,可以同时进行。
服务端: 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的读写功能。