目录
一、用TCP 实现一下两个程序互相聊天(有接收也有发送的操作)
二、实现多个用户连接服务器,并且服务器可以给指定的用户发消息
一、用TCP 实现一下两个程序互相聊天(有接收也有发送的操作)
1、服务器
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
void * send_msg (void * arg)
{
int connect_fd = *(int *)arg ;
// 发送
char * msg = calloc(128,1);
while(1)
{
bzero(msg , 128 );
fgets(msg , 128 , stdin);
int ret_val = send(connect_fd , msg , strlen(msg) , 0 );
if ( ret_val != -1 )
{
printf("send msg succeed : %d byte \n" , ret_val );
}
else{
perror("send error !!");
}
}
}
int main(int argc, char const *argv[])
{
// 创建一个套接字 (购买一台手机)
int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
if (-1 == sock_fd)
{
perror("socket rror");
return -1 ;
}
// 配置自己的IP和端口号等信息
// struct sockaddr_in // IPV4地址结构体
// {
// u_short sin_family;// 地址族
// u_short sin_port;// 端口
// struct in_addr sin_addr;// IPV4 地址
// char sin_zero[8];
// };
int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in my_addr = {
.sin_addr.s_addr = htonl(INADDR_ANY) , // 设置服务器的地址, INADDR_ANY 指本机中任何一个地址
.sin_family = AF_INET , // 使用 IPV4 协议簇
.sin_port = htons(65000) // 设置服务器的端口号为 65000
};
// 绑定地址信息 (IP + 端口号 + 协议簇)
int ret_val = bind( sock_fd, (struct sockaddr *)&my_addr, addrlen);
if (ret_val == -1 )
{
perror("bind error");
return -1 ;
}else{
printf(" bind succeed !!\n") ;
}
// 设置监听 (打开铃声)
if(listen( sock_fd, 5 )) // 设置sock_fd 为监听套接字, 同时可以接收连接请求数为 5 + 4(默认值)
{
perror("listen error");
return -1 ;
}
// 等待连接
struct sockaddr_in from_addr;
int connect_fd = accept( sock_fd , (struct sockaddr *)&from_addr, &addrlen);
if (connect_fd == -1 )
{
perror("connect error");
return -1 ;
}
else{
printf("connect succeed !!\n");
}
// 创建一个接发送数据的线程
pthread_t thread ;
pthread_create( &thread, NULL ,send_msg , (void*)&connect_fd ); // 参数把已连接套接字进行传递
// 聊天
char * msg = calloc(128,1);
while(1)
{
bzero(msg , 128 );
ret_val = recv(connect_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
if ( ret_val != -1 )
{
printf("recv msg : %s " , msg );
}
else{
perror("recv error !!");
}
}
// 关闭套接字
close(sock_fd);
return 0;
}
2、客户端
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
void * send_msg (void * arg)
{
int connect_fd = *(int *)arg ;
// 发送
char * msg = calloc(128,1);
while(1)
{
bzero(msg , 128 );
fgets(msg , 128 , stdin);
int ret_val = send(connect_fd , msg , strlen(msg) , 0 );
if ( ret_val != -1 )
{
printf("send msg succeed : %d byte \n" , ret_val );
}
else{
perror("send error !!");
}
}
}
int main(int argc, char const *argv[])
{
// 创建一个套接字 (购买一台手机)
int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
if (-1 == sock_fd)
{
perror("socket rror");
return -1 ;
}
// 配置自己的IP和端口号等信息
// struct sockaddr_in // IPV4地址结构体
// {
// u_short sin_family;// 地址族
// u_short sin_port;// 端口
// struct in_addr sin_addr;// IPV4 地址
// char sin_zero[8];
// };
int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr = {
.sin_addr.s_addr = inet_addr("192.168.102.2") , // 设置服务器的地址
.sin_family = AF_INET , // 使用 IPV4 协议簇
.sin_port = htons(65000) // 设置服务器的端口号为 65000
};
// 连接服务器
if( connect(sock_fd , (const struct sockaddr *)&server_addr, addrlen))
{
perror("connect error");
return -1 ;
}
// 创建一个接发送数据的线程
pthread_t thread ;
pthread_create( &thread, NULL ,send_msg , (void*)&sock_fd ); // 参数把已连接套接字进行传递
// 聊天
char * msg = calloc(128,1);
int ret_val = -1 ;
while(1)
{
bzero(msg , 128 );
ret_val = recv(sock_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
if ( ret_val != -1 )
{
printf("recv msg : %s " , msg );
}
else{
perror("recv error !!");
}
}
// 关闭套接字
close(sock_fd);
return 0;
}
二、实现多个用户连接服务器,并且服务器可以给指定的用户发消息
1、服务器
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
int num = 0 ; // 数组下标
int connect_arr [10] ;
void * send_msg (void * arg)
{
// 发送
char * msg = calloc(128,1);
while(1)
{
printf("请输入 # 查看当前在线用户并 选择发送对象:\n");
while(getchar() != '#');
printf("**********************************************\n");
for (int i = 0; i < num ; i++)
{
printf("%d 在线用户编号:%d\n" , i , connect_arr[i] );
}
printf("*************请输入需要回信的编号***************\n");
int i ;
scanf("%d" , &i);
while(getchar() != '\n');
bzero(msg , 128 );
fgets(msg , 128 , stdin);
int ret_val = send(connect_arr[i] , msg , strlen(msg) , 0 );
if ( ret_val != -1 )
{
printf("send msg succeed : %d byte \n" , ret_val );
}
else{
perror("send error !!");
}
}
}
void * recv_msg (void * arg)
{
// 把传过来的描述符转换并保存
int connect_fd = *(int *)arg ;
// 聊天
char * msg = calloc(128,1);
int ret_val = -1 ;
while(1)
{
bzero(msg , 128 );
ret_val = recv(connect_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
if ( ret_val != -1 )
{
printf("recv msg from %d client : %s " , connect_fd , msg );
}
else{
perror("recv error !!");
}
}
}
int main(int argc, char const *argv[])
{
// 创建一个套接字 (购买一台手机)
int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
if (-1 == sock_fd)
{
perror("socket rror");
return -1 ;
}
// 配置自己的IP和端口号等信息
// struct sockaddr_in // IPV4地址结构体
// {
// u_short sin_family;// 地址族
// u_short sin_port;// 端口
// struct in_addr sin_addr;// IPV4 地址
// char sin_zero[8];
// };
int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in my_addr = {
.sin_addr.s_addr = htonl(INADDR_ANY) , // 设置服务器的地址, INADDR_ANY 指本机中任何一个地址
.sin_family = AF_INET , // 使用 IPV4 协议簇
.sin_port = htons(65000) // 设置服务器的端口号为 65000
};
// 绑定地址信息 (IP + 端口号 + 协议簇)
int ret_val = bind( sock_fd, (struct sockaddr *)&my_addr, addrlen);
if (ret_val == -1 )
{
perror("bind error");
return -1 ;
}else{
printf(" bind succeed !!\n") ;
}
// 设置监听 (打开铃声)
if(listen( sock_fd, 5 )) // 设置sock_fd 为监听套接字, 同时可以接收连接请求数为 5 + 4(默认值)
{
perror("listen error");
return -1 ;
}
// 创建一个接发送数据的线程
pthread_t thread ;
pthread_create( &thread, NULL ,send_msg , NULL ); // 参数把已连接套接字进行传递
int connect_fd;
pthread_t thread1 ;
while(1)
{
// 等待连接
struct sockaddr_in from_addr;
connect_fd = accept( sock_fd , (struct sockaddr *)&from_addr, &addrlen);
if (connect_fd == -1 )
{
perror("connect error");
return -1 ;
}
else{
if(num >= 9 )
{
break ;
}
printf("connect succeed !!\n");
// 为该用户创建一个线程专门用来接收他发来的消息
pthread_create( &thread1, NULL , recv_msg , (void*)&connect_fd ); // 参数把已连接套接字进行传递
connect_arr[num] = connect_fd;
num ++ ;
}
}
// 等待线程退出
pthread_join(thread , NULL) ;
// 关闭套接字
close(sock_fd);
return 0;
}
2、客户端
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
void * send_msg (void * arg)
{
int connect_fd = *(int *)arg ;
// 发送
char * msg = calloc(128,1);
while(1)
{
bzero(msg , 128 );
fgets(msg , 128 , stdin);
int ret_val = send(connect_fd , msg , strlen(msg) , 0 );
if ( ret_val != -1 )
{
printf("send msg succeed : %d byte \n" , ret_val );
}
else{
perror("send error !!");
}
}
}
int main(int argc, char const *argv[])
{
// 创建一个套接字 (购买一台手机)
int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
if (-1 == sock_fd)
{
perror("socket rror");
return -1 ;
}
// 配置自己的IP和端口号等信息
// struct sockaddr_in // IPV4地址结构体
// {
// u_short sin_family;// 地址族
// u_short sin_port;// 端口
// struct in_addr sin_addr;// IPV4 地址
// char sin_zero[8];
// };
int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr = {
.sin_addr.s_addr = inet_addr("192.168.102.2") , // 设置服务器的地址
.sin_family = AF_INET , // 使用 IPV4 协议簇
.sin_port = htons(65000) // 设置服务器的端口号为 65000
};
// 连接服务器
if( connect(sock_fd , (const struct sockaddr *)&server_addr, addrlen))
{
perror("connect error");
return -1 ;
}
// 创建一个接发送数据的线程
pthread_t thread ;
pthread_create( &thread, NULL ,send_msg , (void*)&sock_fd ); // 参数把已连接套接字进行传递
// 聊天
char * msg = calloc(128,1);
int ret_val = -1 ;
while(1)
{
bzero(msg , 128 );
ret_val = recv(sock_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
if ( ret_val != -1 )
{
printf("recv msg : %s " , msg );
}
else{
perror("recv error !!");
}
}
// 关闭套接字
close(sock_fd);
return 0;
}