完成聊天室 需要聊天 那就要建立连接 建立连接后 就发送信息
建立连接 和 发送信息 需要什么函数 ?
服务器 和 客户端 各自需要什么?
服务器:
1.1 socket :创建一个Socket 用以监听 (一个空的通道 一头将要连服务器 一头将要连客户)
1.2 Bind :绑定 IP 和 端口号
1.3 Listen :监听 两个参数 参数1 :socket 那个通道
参数2 :数字 监听队列的大小 : 同一时刻 允许的最大连接数
1.4 accept :接受客户发起的连接 参数 1 : socket
参数 2 :客户端的IP 和端口...
参数 3 :结构体的长度
1.5 send 和 recv
客户端:
2.1 socket : 创建一个socket
2.2 connect : 连接
具体函数都可以利用man (manual)手册进行查询 :例如man 2 socket 记得把其中的头文件加入自己的代码中
标准的man手册主要分为8个章节,分别为:
1 User Commands // 用户命令
2 System Calls // 系统调用
3 C Library Functions // C函数库调用
4 Devices and Special Files // 设备文件和特殊文件
5 File Formats and Conventions // 配置文件及格式
6 Games et. Al. // 游戏
7 Miscellanea // 杂项
8 System Administration tools and Deamons // 管理类命令
使用格式:
man [章节] COMMAND
q Q ZZ 退出
基本的函数
TCPserver.c :
1.1 Socket
创建一个int 型socketid接socket的返回值 返回值是一个文件描述符
一般的,文件描述符: 0 标准输入 1 标准输出 2 标准错误输出
0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr,
0就是stdin,1就是stdout,2就是stderr
(函数原型)int socket(int domain, int type, int protocol);
Domain: 地址族协议 我们一般用PF_INET (ipv4协议)
Type: 套接字的类型 (TCP用SOCK_STREAM)(UDP用 SOCK_DGRAM)
前面博客中已经告知所有相关知识点
Protocol: 一般默认为0 这个参数是由前面两个就决定好的 不需要特意再去指定
1.2 Bind
创建一个int型 ret 接bind的返回值 返回值 代表是否绑定成功
(函数原型)int bind ( int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
Sockfd: 文件描述符 指定绑定谁 (在服务器创建了socket之后当然先把自己绑在通道的一端,等待客户向自己发起连接)
my_addr: 是一个结构体:struct sockaddr
Addrlen: 是第二个参数 结构体的大小
**所以在第二个参数这里 我们就需要在开始bind前创建一个结构体
Struct sockaddr_in server_addr;
并且对这个结构体 内部的数据 进行初始化
memset(&server_addr, 0, sizeof(struct sockaddr_in)); //清空原始数据 防止出错(这个函数需要+string.h头文件)
server_addr.sin_family = AF_INET; //地址族协议 用ipv4
server_addr.sin_port = PORT; //指定端口号 PORT自己在最开始指定(我是8888)
server_addr.sin_addr.s_addr = inet_addr("192.168.222.128");
//指定服务器的ip地址为 192.168.222.128
//这里 因为系统内存放的数据是二进制(长整型)所以用到转换函数 inet_addr( )
//函数原型in_addr_t inet_addr(const char* strptr);
//返回:若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址
1.3 Listen
创建一个int型 ret 接Listen的返回值 返回值 代表是否绑定成功
(函数原型)int listen(int sockfd, int backlog);
Sockfd: 监听服务器创建的通道上是否有请求
Backlog: 同一时刻 允许的最大连接数
1.4 Accept
创建一个int型 fd [ i ] 接Listen的返回值 返回值 代表接受到哪个客户端发送来的请求
//fd [ i ] 因为你接受到的客户请求可能不止一个 你需要把他们都记下来 一个个处理
//但是fd [ i ] 的值是从4开始的 前面说过了 012 标准--输入、输出、错误输出 3 是自己创建的sockfd
(函数原型)int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Sockfd: 文件描述符 指示哪个客户的文件描述符有变化
ddr: 是一个结构体:struct sockaddr 代表接受到的 客户的地址
Addrlen: 是第二个参数 结构体的大小
**所以在第二个参数这里 我们同样要在开始前创建一个结构体
Struct sockaddr_in client_addr;
memset(&server_addr, 0, sizeof(struct sockaddr_in)); //清空原始数据 防止出错
1.5 创建线程pthread_create
创建一个int型 ret接pthread_create的返回值 返回值 代表线程是否创建成功
(函数原型)int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
restrict thread:开始就创建一个pthread_t tid[100]; 用以创建线程 因为一次接受就需要一次线程的创建;
restrict attr: 用于指定各种不同的线程属性,默认为NULL
*(*start_routine)(void*): 线程创建后 用此处对应的函数 进行线程的处理(完成此线程需要的功能)
restrict arg: &fd[ i ] : 最后一个参数是运行函数的参数 哪个客户调用这个函数了
TCPclient.c
2.1 soket()
同上面服务器的一样
2.2 connect()
(函数原型)int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
Socket: 很明显和上面差不多 这里的sockfd就是客户自己创建的
serv_addr: 和上面一样 自己一开始就创建一个结构体就行 记得也要初始化
Addrlen: 大小就是结构体的大小
最后就是写一个 send 一个recv 函数用以接收和发送信息了。
TCPserver.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 8888
struct info
{
char buf[100];
int to_fd;
};
struct info SendBuf;
void *HandlerClientThread(void *arg)
{
int ret;
while (1)
{
ret = recv(*(int *)arg, &SendBuf, sizeof(SendBuf), 0);
if (-1 == ret)
{
perror("recv");
return;
}
//printf("Receive From %d : %s\n", *(int *)arg, buf);
ret = send(SendBuf.to_fd, &SendBuf, sizeof(SendBuf), 0);
if (-1 == ret)
{
perror("send");
return;
}
memset(&SendBuf, 0, sizeof(SendBuf));
}
}
int main()
{
int sockfd, ret, fd[100] = {0}, length, i = 0;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
char buf[100] = {0};
pthread_t tid[100];
printf("START SERVER!\n");
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("sockfd");
exit(1);
}
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = PORT;
// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_addr.s_addr = inet_addr("192.168.222.128");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("bind");
exit(1);
}
printf("WAITTING FOR CONNECT...\n");
while(1)
{
ret = listen(sockfd, 5);
if (-1 == ret)
{
perror("listen");
exit(1);
}
length = sizeof(client_addr);
fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length);
if (-1 == fd[i])
{
perror("accept");
exit(1);
}
printf("ACCEPT %d ,Port = %d!\n", fd[i], client_addr.sin_port);
ret = pthread_create(&tid[i], NULL, HandlerClientThread, (void *)&fd[i]);
if (0 != ret)
{
perror("create");
exit(1);
}
i++;
}
return 0;
}
TCPclient.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 8888
struct info
{
char buf[100];
int to_fd;
};
struct info SendBuf;
void *MyReceive(void *arg)
{
int ret;
while (1)
{
ret = recv(*(int *)arg, &SendBuf, sizeof(SendBuf), 0);
if (-1 == ret)
{
perror("recv");
return;
}
printf("\t\t\t%s\n", SendBuf.buf);
memset(&SendBuf, 0, sizeof(SendBuf));
}
}
//int main()
int main(int argc, char *argv[])
{
int sockfd, ret;
struct sockaddr_in server_addr;
char buf[100] = {0};
pthread_t tid;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = PORT;
// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_addr.s_addr = inet_addr(argv[1]);//自己从运行程序的时候传进来
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("connect");
exit(1);
}
ret = pthread_create(&tid, NULL, MyReceive, (void *)&sockfd);
if (0 != ret)
{
perror("create");
exit(1);
}
while(1)
{
scanf("%s %d", SendBuf.buf, &SendBuf.to_fd);
ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
if (-1 == ret)
{
perror("sand");
exit(1);
}
}
return 0;
}