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

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

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

服务器端程序:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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;

charipaddr[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_tpid;

charbuf[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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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;

charbuf[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);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值