實現了服務端和用戶端之間的相互聊天,不收順序限制,可以同時進行。
服務端: 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的讀寫功能。