socket ipv4 客户端
1)创建soket_fd
client_sd = socket(AF_INET,SOCK_STREAM,0);
2)初始化socket信息 socketaddr_in,它里面有3个参数,
sin_family(这个用来定义使用哪种协议tcp udp)
port 端口号 int类型
sin_addr.s_addr ip地址是个整型,用int_addr()转
struct socketaddr_in client_sockaddr;
client_sockaddr.sin_port = htons(port);
client_sockaddr.sin_family = AF_INET; tcp
client_sockaddr.sin_addr.s_addr = inet_addr(ip_src);
3)连接服务端
int con_rv = connect(client_sd,(struct sockaddr*)&client_sockaddr,sizeof(client_sockaddr));
如果con_rv =-1 就是连接失败了
4)创建发送线程和连接线程
pthread_create(线程1指针,线程属性,线程处理函数,给线程的参数)
pthread_t thrd1; ptread_t thrd2;
pthread_create(&thrd1,NULL,thread_send,&client_sd);
pthread_create(&thrd2,NULL,thread_recv,&client_sd);
pthread_create()==0 表示创建线程ok
pthread_join(&thrd1,NULL);
pthread_join(&thrd2,NULL);
5)发送线程
send(文件id,发送字节,发送字节数,标志);
send(client_sd,buf,sizeof(buf),0); //返回发送字节数,或者-1(失败)
6)接收线程
char buf[1024];
rv = recv(client_sd,buf,sizeof(buf),0); 大于0表示有数据返回
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFSIZE 1024
#define ERRORCODE -1
static void *thread_send(void *arg){
char buf[BUFFSIZE];
int sd = *(int *)arg;
while(1){
memset(buf,0,sizeof(buf));//给buf清零
read(STDIN_FILENO,buf,sizeof(buf));
if(send(sd,buf,strlen(buf),0)==-1){
printf("send error:%s \n",strerror(errno));
break;
}
}
return NULL;
}
static void *thread_recv(void *arg){
char buf[BUFFSIZE];
int sd = *(int *)arg;
while(1){
memset(buf,0,sizeof(buf));
int rv = recv(sd,buf,sizeof(buf),0);
if(rv<=0){
if(rv==0){
printf("server have already full \n");
exit(0);
}
printf("receive error:%s\n",strerror(errno));
break;
}
printf("%s",buf);
}
return NULL;
}
int run_client(char *ip_str,int port){
int client_sd;
int con_rv;
pthread_t thrd1,thrd2;
struct sockaddr_in client_sockaddr; //定义IP地址结构
client_sd = socket(AF_INET,SOCK_STREAM,0);
if(client_sd == -1){
printf("socket create error :%s \n",strerror(errno));
return ERRORCODE;
}
memset(&client_sockaddr,0,sizeof(client_sockaddr));
client_sockaddr.sin_port = htons(port); //set server port
client_sockaddr.sin_family = AF_INET; //set tcp ip
client_sockaddr.sin_addr.s_addr = inet_addr(ip_str); //set server ipaddress 将字符串的IP地址转换成int型,客户端要连接的服务端ip地址
// con_rv = connect(client_sd,(struct sockaddr*)client_sockaddr,sizeof(client_sockaddr));
con_rv = connect(client_sd, (struct sockaddr*) &client_sockaddr,sizeof(client_sockaddr));
// 调用connect连接到指定的ip地址和端口号,建立连接后通过socket描述符通讯
if(con_rv == -1){
printf("connect error:%s\n",strerror(errno));
return ERRORCODE;
}
if(pthread_create(&thrd1,NULL,thread_send,&client_sd)!=0){
printf("create thread thrd1 error:%s\n",strerror(errno));
return ERRORCODE;
}
if(pthread_create(&thrd2,NULL,thread_recv,&client_sd)!=0){
printf("create thread thrd2 error:%s\n",strerror(errno));
return ERRORCODE;
}
pthread_join(thrd2,NULL);
pthread_join(thrd1,NULL);
close(client_sd);
return 0;
}
int main(int argc,char *argv[]){
if(argc<3){
printf("Usage:ip port,example:127.0.0.1 8080 \n");
return ERRORCODE;
}
int port = atoi(argv[2]);
char *ip_str = argv[1];
run_client(ip_str,port);
return 0;
}
// 字节流套接口(如tcp套接口)上的read和write函数所表现的行为不同于通常的文件IO。字节流套接口上的读或写输入或输出的字节数可能比要求的数量少,
// 但这不是错误状况,原因是内核中套接口的缓冲区可能已达到了极限。此时所需的是调用者再次调用read或write函数,以输入或输出剩余的字节。
// 可以使用readn函数来实现循环读取以解决这个问题:
ssize_t readn(int fd,void *vptr,size_t n){
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while(nleft>0){
if((nread==read(fd,ptr,nleft))<0){
if(errno == EINTR){
nread = 0;
}else{
return (-1);
}
}else if(nread ==0){
break; //eof
}
nleft -= nread;
ptr +=nread;
}
return (n-nleft); /*return >=0*/
}
参考:【socket】C语言的Socket网络编程_c语言socket-CSDN博客