服務器端:Redhat 6.4 server 64bit
客戶端: Ubuntu 14.04 64bit
客戶端:
1. 根據傳入的參數建立socket 並與服務器建立連接。
2. 連接成功後,開兩個線程,一個用於接收來自服務器端的消息;另一個用於讀取用戶輸入,再把輸入內容發送到服務器。
3. 當接收到服務器端斷開消息後,退出程序。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
/*客戶端接收線程*/
void *recvsocket(void *arg)
{
int st =*(int *)arg;
char buf[1024];
int rc = 0;
while(1)
{
memset(buf, 0, sizeof(buf));
rc = recv(st, buf, sizeof(buf), 0);
if(rc <= 0)
{
exit(0);
}
printf("%s", buf);
}
return NULL;
}
/*客戶端發送線程*/
void *sendsocket(void *arg)
{
int st = *(int *)arg;
char buf[1024];
int rc =0;
while(1)
{
memset(buf, 0, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
rc = send(st, buf, strlen(buf), 0);
if(rc <= 0)
{
break;
}
}
return NULL;
}
int main(int arg, char **args)
{
if(arg < 3)
{
printf("usage: client ipaddress port\n");
return -1;
}
int port = atoi(args[2]);
//創建socket
int st = socket(AF_INET, SOCK_STREAM, 0);
if(st == -1)
{
perror("create socket error:");
return -2;
}
//定義一個IP地址結構
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; //指定地址結構類型
addr.sin_port = htons(port); //指定端口號
addr.sin_addr.s_addr = inet_addr(args[1]);
//調用connect連接指定address的服務器
if(connect(st, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("connect error:");
return -3;
}
pthread_t thrd1, thrd2;
pthread_create(&thrd1, NULL, recvsocket, &st);
pthread_create(&thrd2, NULL, sendsocket, &st);
pthread_join(thrd1, NULL);
pthread_join(thrd2, NULL);
return 0;
}
服務器端:
1. 根據傳入的參數建立socket,並等待客戶端連接到來。
2. 當收到一個客戶端請求時,置連接狀態爲1,以表示不再接收其他客戶端連接請求(爲了避免聊天時,不知道發給誰),開兩個線程,一個用於接收客戶端的消息,另一個發送消息。
3. 當服務器接收到客戶端斷開連接消息,把連接狀態置爲0,服務器可以再接收其他客戶端的連接。爲了避免同時改變連接狀態的值,在改變連接狀態的前加鎖。並把發送消息線程取消。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
/*結構體:用於傳送消息到線程中*/
struct ps_info
{
int st;
pthread_t *p;
};
/*標誌:是否已經有客戶端連接*/
int status = 0;
/*鎖*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/*服務器接收線程*/
void *recvsocket(void *arg)
{
struct ps_info ps1 = *(struct ps_info *)arg;
int st =ps1.st;
char buf[1024];
int rc = 0;
while(1)
{
memset(buf, 0, sizeof(buf));
rc = recv(st, buf, sizeof(buf), 0);
if(rc <= 0)
{
break;
}
printf("%s", buf);
}
pthread_mutex_lock(&mutex);
status = 0; //把連接狀態置0
pthread_mutex_unlock(&mutex);
pthread_cancel(*ps1.p); //把發送線程取消
return NULL;
}
/*服務器發送線程*/
void *sendsocket(void *arg)
{
int st = *(int *)arg;
char buf[1024];
int rc =0;
while(1)
{
memset(buf, 0, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
rc = send(st, buf, strlen(buf), 0);
if(rc <= 0)
{
break;
}
}
return NULL;
}
int main(int arg, char **args)
{
if(arg < 3)
{
printf("usage: client ipaddress port\n");
return -1;
}
int port = atoi(args[2]);
/*創建socket*/
int st = socket(AF_INET, SOCK_STREAM, 0);
if(st == -1)
{
perror("create socket error:");
return -2;
}
//定義一個IP地址結構
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; //指定地址結構類型
addr.sin_port = htons(port); //指定端口號
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(st, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("bind error:");
return -2;
}
if(listen(st, 20) == -1)
{
perror("listen error:");
return -2;
}
int client_st = 0;
socklen_t len =0;
struct sockaddr_in client_addr;
pthread_t thrd1, thrd2;
while(1)
{
memset(&client_addr, 0, sizeof(client_st));
len = sizeof(client_addr);
client_st = accept(st, (struct sockaddr *)&client_addr, &len);
pthread_mutex_lock(&mutex);
status++;
pthread_mutex_unlock(&mutex);
if(status > 1)
{
close(client_st);
continue;
}
if(client_st == -1)
{
perror("accept error:");
return -3;
}
printf("accept by %s\n", inet_ntoa(client_addr.sin_addr));
struct ps_info ps1;
ps1.st = client_st;
ps1.p = &thrd1;
pthread_create(&thrd1, NULL, recvsocket, &ps1);
pthread_detach(thrd1);
pthread_create(&thrd2, NULL, sendsocket, &client_st);
pthread_detach(thrd2);
}
close(st);
return 0;
}