您的位置:首页 > 运维架构 > Linux

linux下socket实现多个客户端与服务器的通信

2016-09-25 13:30 423 查看
学习完《UNIX环境高级编程》套接字一章的内容之后,自己实现了单个客户端与服务器的通信程序,后面想想要是多个客户端如何与服务器通信呢?这就有了这篇文章。

这里采用的是用多线程实现多客户端与服务器的通信,多线程的思路参考了Linux
C利用Socket套接字进行服务器与多个客户端进行通讯,在此感谢原文章作者。

服务器端程序:

#include<stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <pthread.h>

#define BUFLEN 128

#define QLEN   10

#define DATALEN 200

#define SERVPORT 48800

#define HOST_NAME_MAX 256
#define IPLEN  16

//store accept id of client connect to server

int acceptfd[QLEN];
//number of client connect to server

int acceptnum = 0;

//information from main thread to created thread
struct threadinfo
{
int 	clfd;
char	ipaddr[IPLEN];
int 	port;
};

void sys_err(char *errinfo)

{

if(NULL == errinfo)

{

return;

}

perror("errinfo");

exit(0);

}

int initsrver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)

{

int fd;

int err = 0;

int reuse = -1;

if((fd = socket(addr->sa_family, type, 0)) < 0)

{

return -1;

}
//set socket option

if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0)

goto errout;

if(bind(fd, addr, alen) < 0)

goto errout;

if(type == SOCK_STREAM || type == SOCK_SEQPACKET)

{
//listen

if(listen(fd, qlen) < 0)

goto errout;

}

return fd;

errout:

err = errno;

close(fd);

errno = err;

return -1;

}

void *recvmessage(void *arg)

{

char buf[BUFLEN];

char recvtitle[DATALEN] = "receive from ";

int n;
struct threadinfo *ti = arg;

memset(buf, 0, BUFLEN);

sprintf(recvtitle, "%s%s:%d ", recvtitle, ti->ipaddr, ti->port);

while((n = recv(ti->clfd, buf, BUFLEN, 0)) > 0)

{

write(STDOUT_FILENO, recvtitle, strlen(recvtitle));

write(STDOUT_FILENO, buf, n);

memset(buf, 0, BUFLEN);

}

if(n < 0)

printf("recv error\n");

}

void *acceptThread(void *sockfd)

{

int clfd;

const char *addr;

char buf[BUFLEN];

int n;

char abuf[INET_ADDRSTRLEN];

struct sockaddr_in clientsockaddr;

int clientlen;

int err;

pthread_t recvtid;
struct threadinfo ti;

clientlen = sizeof(clientsockaddr);
//always accept new client to accept a lot of client

while(1)

{

if((clfd = accept(*(int *)sockfd, (struct sockaddr *)&clientsockaddr, &clientlen)) < 0)

sys_err("accept error");

printf("%s:%d login in to server\n", inet_ntoa(clientsockaddr.sin_addr), clientsockaddr.sin_port);

//when accept client, store it's accept id

acceptfd[acceptnum++] = clfd;

//create thread to receive message of every client
ti.clfd = clfd;
strcpy(ti.ipaddr, inet_ntoa(clientsockaddr.sin_addr));
ti.port = clientsockaddr.sin_port;

if((err = pthread_create(&recvtid, NULL, recvmessage, &ti)) != 0)

sys_err("pthread_create recvmessage error");

}

}

int communication(int sockfd)

{

int 	clfd;

pid_t	pid;

char	buf[BUFLEN];

int 	fd;

int 	err;

pthread_t acpttid;

int 	i;

memset(buf, 0, BUFLEN);

//create thread to accept client, always accept to accept a lot of client

if((err = pthread_create(&acpttid, NULL, acceptThread, &sockfd)) != 0)

sys_err("pthread_create acceptThread error");

//send message to client, but only send the same mesage to all connected client now

memset(buf, 0, BUFLEN);

while(1)

{

if(fgets(buf, BUFLEN, stdin) != NULL)

{
//print the num of accept client connect to server

printf("acceptnum: %d\n", acceptnum);

for (i = 0; i < acceptnum; ++i)

{

send(acceptfd[i], buf, strlen(buf), 0);

}

memset(buf, 0, BUFLEN);

}

}

close(clfd);

}

int main(int argc, char *argv[])

{

struct sockaddr_in serversockaddr, clientsockaddr;

int 	sockfd, clientfd;

int err, n;

if(argc != 1)

{

printf("usage: %s\n", argv[0]);

exit(0);

}

serversockaddr.sin_family = AF_INET;

serversockaddr.sin_port = htons(SERVPORT);

serversockaddr.sin_addr.s_addr = INADDR_ANY;

bzero(&(serversockaddr.sin_zero), 8);

if((sockfd = initsrver(SOCK_STREAM, (struct sockaddr *)&serversockaddr, sizeof(struct sockaddr), QLEN)) > 0)

{
//start communication

communication(sockfd);

exit(0);

}

exit(0);

}


客户端程序:
#include<stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <pthread.h>

#define SERVPORT 48800

#define MAXSLEEP 128

#define BUFLEN 128

#define DATALEN 200

int connect_retry(int domain, int type, int protocol, const struct sockaddr *addr)

{

int numsec, fd;

//try to connect with exponential backoff

for(numsec = 1; numsec <= MAXSLEEP; numsec <<= 1)

{

if((fd = socket(domain, type, protocol)) < 0)

return -1;

if(connect(fd, addr, sizeof(struct sockaddr)) == 0)

{

return fd;

}

close(fd);

//delay before trying again

if(numsec <= MAXSLEEP/2)

sleep(numsec);

}

return -1;

}

void *sendmessage(void *arg)

{

int sockfd;

char	buf[BUFLEN];

sockfd = *(int *)arg;

memset(buf, 0, BUFLEN);

while(fgets(buf, BUFLEN, stdin) != NULL)

{

send(sockfd, buf, strlen(buf), 0);

memset(buf, 0, BUFLEN);

}

}

void communication(int sockfd)

{

int n;

pid_t pid;

char buf[BUFLEN];

char *recvtitle = "received from server: ";

int fd;

int err;

pthread_t tid;

memset(buf, 0, BUFLEN);

//create thread to send message

if(err = pthread_create(&tid, NULL, sendmessage, &sockfd))

{

printf("pthread_create error\n");

exit(0);

}

//receive message

while(1)

{

while((n = recv(sockfd, buf, BUFLEN, 0)) > 0)

{

write(STDOUT_FILENO, recvtitle, strlen(recvtitle));

write(STDOUT_FILENO, buf, n);

memset(buf, 0, BUFLEN);

}

if(n < 0)

printf("recv error\n");

}

}

int main(int argc, char *argv[])

{

int sockfd, err;

struct sockaddr_in serversockaddr;

const char	*addr;

char abuf[INET_ADDRSTRLEN];

struct hostent *host;

if(argc != 2)

{

printf("usage: %s hostname\n", argv[0]);

exit(0);

}

if((host = gethostbyname(argv[1])) == NULL)

{

perror("gethostbyname");

exit(0);

}

serversockaddr.sin_family = AF_INET;

serversockaddr.sin_port = htons(SERVPORT);

serversockaddr.sin_addr = *((struct in_addr *)host->h_addr);

bzero(&(serversockaddr.sin_zero), 0);

if((sockfd = connect_retry(serversockaddr.sin_family, SOCK_STREAM, 0, (struct sockaddr *)&serversockaddr)) < 0)

{

err = errno;

}

else

{

communication(sockfd);

exit(0);

}

printf("can't connect to %s\n", argv[1]);

exit(0);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息